Initial commit for gisaf/fastapi
This commit is contained in:
commit
adce44722f
1361 changed files with 42521 additions and 0 deletions
283
src/app/map/gisaf-mapbox/gisaf-ruler.directive.ts
Normal file
283
src/app/map/gisaf-mapbox/gisaf-ruler.directive.ts
Normal file
|
@ -0,0 +1,283 @@
|
|||
import { ElementRef, Input, ViewChild, Directive, HostListener } from '@angular/core'
|
||||
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
import { MatButton } from '@angular/material/button'
|
||||
|
||||
import { Position } from 'geojson'
|
||||
import distance from '@turf/distance'
|
||||
import { Units } from '@turf/helpers'
|
||||
//import { GeoJSONSource } from 'maplibre-gl'
|
||||
import { MapService } from '@maplibre/ngx-maplibre-gl'
|
||||
import { POINT_CONVERSION_HYBRID } from 'constants'
|
||||
|
||||
|
||||
const LAYER_LINE = 'gisaf-ruler-line'
|
||||
const LAYER_SYMBOL = 'gisaf-ruler-symbol'
|
||||
const LAYER_DISTANCE = 'gisaf-ruler-dist'
|
||||
const LAYER_MARKER = 'gisaf-ruler-marker'
|
||||
const SOURCE_LINE = 'gisaf-ruler-line-source'
|
||||
const SOURCE_SYMBOL = 'gisaf-ruler-symbol-source'
|
||||
|
||||
@Directive({
|
||||
selector: '[gisafRuler]'
|
||||
})
|
||||
export class GisafRulerDirective {
|
||||
segments: Position[][] = []
|
||||
startingPoint: Position
|
||||
labels: string[]
|
||||
distances: number[]
|
||||
// XXX: remove typings (maplibre 2.x)
|
||||
//lineSource: GeoJSONSource
|
||||
//symbolSource: GeoJSONSource
|
||||
lineSource: any
|
||||
symbolSource: any
|
||||
active: boolean = false
|
||||
@Input() color: string = '#4264fb'
|
||||
@Input() units: Units = <Units>'kilometers'
|
||||
@Input() font: string[] = ['Noto Sans Regular']
|
||||
@Input() fontSize: number = 14
|
||||
@Input() markerSize: number = 3
|
||||
@Input() lineWidth: number = 1
|
||||
@Input() secondaryColor: string = 'white'
|
||||
@Input() fontHalo: number = 2
|
||||
@ViewChild(MatButton) button: MatButton
|
||||
clickSubscription: Subscription
|
||||
lineDrawn: boolean
|
||||
|
||||
constructor(
|
||||
public elementRef: ElementRef,
|
||||
private mapService: MapService
|
||||
) {}
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.active ? this.stop() : this.start()
|
||||
}
|
||||
|
||||
start() {
|
||||
this.active = true
|
||||
this.elementRef.nativeElement.classList.add('-active')
|
||||
this.segments = []
|
||||
this.labels = []
|
||||
this.distances = []
|
||||
this.lineDrawn = false
|
||||
this.startingPoint = undefined
|
||||
this.addLayers()
|
||||
this.mapService.mapCreated$.subscribe(
|
||||
() => {
|
||||
this.clickSubscription = this.mapService.mapEvents.mapClick.subscribe(
|
||||
evt => this.onMapClick(evt)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.active = false
|
||||
this.elementRef.nativeElement.classList.remove('-active')
|
||||
this.clickSubscription.unsubscribe()
|
||||
this.removeLayers()
|
||||
}
|
||||
|
||||
/*
|
||||
updateLabels() {
|
||||
let sum = 0
|
||||
this.labels = this.segments.map((coordinate, index) => {
|
||||
if (index === 0) return this.labelFormat(0)
|
||||
sum += distance(this.segments[index - 1], coordinate, {units: this.units})
|
||||
return this.labelFormat(sum)
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
updateDistances() {
|
||||
this.distances = []
|
||||
this.segments.map((coordinate, index) => {
|
||||
if (index === 0) return
|
||||
this.distances.push(
|
||||
distance(this.segments[index - 1], coordinate, {units: this.units})
|
||||
)
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
labelFormat(n) {
|
||||
return n == 0 ? '0' : n < 1 ? `${(n * 1000).toFixed(2)} m`: `${n.toFixed(3)} km`
|
||||
}
|
||||
|
||||
onMapClick(evt) {
|
||||
const newCoordinate = [evt.lngLat.lng, evt.lngLat.lat]
|
||||
|
||||
if (this.lineDrawn) {
|
||||
if (evt.originalEvent.ctrlKey) {
|
||||
this.segments.push([this.startingPoint, newCoordinate])
|
||||
}
|
||||
else {
|
||||
this.startingPoint = newCoordinate
|
||||
this.lineDrawn = false
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.startingPoint) {
|
||||
this.segments.push([this.startingPoint, newCoordinate])
|
||||
this.lineDrawn = true
|
||||
}
|
||||
else {
|
||||
this.startingPoint = newCoordinate
|
||||
}
|
||||
}
|
||||
|
||||
//else {
|
||||
// if (!this.startingPoint || this.multiLineMode) {
|
||||
// this.startingPoint = newCoordinate
|
||||
// }
|
||||
// else {
|
||||
// this.segments.push([this.startingPoint, newCoordinate])
|
||||
// this.startingPoint = undefined
|
||||
// }
|
||||
// this.multiLineMode = false
|
||||
//}
|
||||
|
||||
//this.updateLabels()
|
||||
//this.updateDistances()
|
||||
|
||||
this.lineSource.setData(this.getLineStringFeatures())
|
||||
this.symbolSource.setData(this.getPointFeatureCollection())
|
||||
}
|
||||
|
||||
addLayers() {
|
||||
const map = this.mapService.mapInstance
|
||||
map.addSource(SOURCE_LINE, {
|
||||
type: 'geojson',
|
||||
data: this.getLineStringFeatures()
|
||||
}
|
||||
)
|
||||
|
||||
map.addSource(SOURCE_SYMBOL, {
|
||||
type: 'geojson',
|
||||
data: this.getPointFeatureCollection()
|
||||
})
|
||||
|
||||
map.addLayer({
|
||||
id: LAYER_LINE,
|
||||
type: 'line',
|
||||
source: SOURCE_LINE,
|
||||
paint: {
|
||||
'line-color': this.color,
|
||||
'line-width': this.lineWidth,
|
||||
'line-dasharray': [2, 2]
|
||||
},
|
||||
})
|
||||
|
||||
/*
|
||||
map.addLayer({
|
||||
id: LAYER_SYMBOL,
|
||||
type: 'symbol',
|
||||
source: SOURCE_SYMBOL,
|
||||
layout: {
|
||||
'text-field': '{text}',
|
||||
'text-font': this.font,
|
||||
'text-anchor': 'top',
|
||||
'text-size': this.fontSize,
|
||||
'text-offset': [0, 0.8],
|
||||
'text-allow-overlap': true,
|
||||
},
|
||||
paint: {
|
||||
'text-color': this.color,
|
||||
//'text-halo-color': this.secondaryColor,
|
||||
//'text-halo-width': this.fontHalo,
|
||||
},
|
||||
})
|
||||
*/
|
||||
|
||||
map.addLayer({
|
||||
id: LAYER_DISTANCE,
|
||||
type: 'symbol',
|
||||
source: SOURCE_LINE,
|
||||
layout: {
|
||||
'text-field': ['get', 'dist'],
|
||||
'text-font': this.font,
|
||||
//'text-anchor': 'top',
|
||||
'text-size': this.fontSize,
|
||||
//'text-offset': [0, 0.8],
|
||||
'text-allow-overlap': true,
|
||||
'symbol-placement': 'line-center'
|
||||
},
|
||||
paint: {
|
||||
'text-color': this.color,
|
||||
'text-halo-color': this.secondaryColor,
|
||||
'text-halo-width': this.fontHalo,
|
||||
},
|
||||
})
|
||||
|
||||
map.addLayer({
|
||||
id: LAYER_MARKER,
|
||||
type: 'circle',
|
||||
source: SOURCE_SYMBOL,
|
||||
paint: {
|
||||
'circle-radius': this.markerSize,
|
||||
'circle-color': this.color,
|
||||
},
|
||||
})
|
||||
|
||||
//this.lineSource = <GeoJSONSource>map.getSource(SOURCE_LINE)
|
||||
//this.symbolSource = <GeoJSONSource>map.getSource(SOURCE_SYMBOL)
|
||||
this.lineSource = map.getSource(SOURCE_LINE)
|
||||
this.symbolSource = map.getSource(SOURCE_SYMBOL)
|
||||
}
|
||||
|
||||
removeLayers() {
|
||||
const map = this.mapService.mapInstance
|
||||
map.removeLayer(LAYER_LINE)
|
||||
//map.removeLayer(LAYER_SYMBOL)
|
||||
map.removeLayer(LAYER_DISTANCE)
|
||||
map.removeLayer(LAYER_MARKER)
|
||||
map.removeSource(SOURCE_LINE)
|
||||
map.removeSource(SOURCE_SYMBOL)
|
||||
}
|
||||
|
||||
getLineStringFeatures(): GeoJSON.FeatureCollection {
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: this.segments.map(
|
||||
segment => ({
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
dist: this.labelFormat(distance(segment[0], segment[1]))
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: segment,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getPointFeatureCollection(): GeoJSON.FeatureCollection {
|
||||
let points: Position[] = []
|
||||
this.segments.forEach(
|
||||
s => {
|
||||
points.push(s[0], s[1])
|
||||
}
|
||||
)
|
||||
if (!!this.startingPoint) {
|
||||
points.push(this.startingPoint)
|
||||
}
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: points.map(
|
||||
p => ({
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: p,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue