@xyo-network/react-map 7.5.8 → 7.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/Components/MapBox.d.ts.map +1 -1
- package/dist/browser/Components/MapBoxPoints.d.ts.map +1 -1
- package/dist/browser/MapBoxClasses/MapHeat.d.ts.map +1 -1
- package/dist/browser/MapBoxClasses/MapSettings.d.ts.map +1 -1
- package/dist/browser/hooks/useDynamicMapResize.d.ts.map +1 -1
- package/dist/browser/hooks/useQuadKeyPayloadsToFeatures.d.ts.map +1 -1
- package/dist/browser/index.mjs +481 -714
- package/dist/browser/index.mjs.map +1 -1
- package/package.json +159 -36
- package/src/Components/AnimatedHeatMap.tsx +0 -61
- package/src/Components/AnimatedHeatMapLoaded.tsx +0 -61
- package/src/Components/FeaturesToLayersMap.ts +0 -8
- package/src/Components/HeatMapSettings.ts +0 -11
- package/src/Components/LayerAnimator.tsx +0 -119
- package/src/Components/Legend.tsx +0 -36
- package/src/Components/Legends/ColorGradient.tsx +0 -35
- package/src/Components/Legends/index.ts +0 -1
- package/src/Components/MapBox.stories.tsx +0 -92
- package/src/Components/MapBox.tsx +0 -79
- package/src/Components/MapBoxHeat.tsx +0 -19
- package/src/Components/MapBoxPoints.tsx +0 -99
- package/src/Components/MapSettingsComponents/Setting.tsx +0 -36
- package/src/Components/MapSettingsComponents/SettingsBox.tsx +0 -34
- package/src/Components/MapSettingsComponents/index.ts +0 -2
- package/src/Components/index.ts +0 -11
- package/src/Contexts/HeatMapInitializer/Context.ts +0 -7
- package/src/Contexts/HeatMapInitializer/Provider.tsx +0 -93
- package/src/Contexts/HeatMapInitializer/State.ts +0 -8
- package/src/Contexts/HeatMapInitializer/index.ts +0 -3
- package/src/Contexts/HeatMapInitializer/useHeatMapInitializer.tsx +0 -13
- package/src/Contexts/MapBoxInstance/Context.ts +0 -7
- package/src/Contexts/MapBoxInstance/Provider.tsx +0 -26
- package/src/Contexts/MapBoxInstance/State.ts +0 -8
- package/src/Contexts/MapBoxInstance/index.ts +0 -3
- package/src/Contexts/MapBoxInstance/useMapBoxInstance.tsx +0 -13
- package/src/Contexts/MapSettings/Context.ts +0 -7
- package/src/Contexts/MapSettings/Provider.tsx +0 -43
- package/src/Contexts/MapSettings/State.ts +0 -7
- package/src/Contexts/MapSettings/index.ts +0 -3
- package/src/Contexts/MapSettings/useMapSettings.tsx +0 -11
- package/src/Contexts/index.ts +0 -3
- package/src/Layers/Builders/LocationHeatMapLayerBuilder.ts +0 -36
- package/src/Layers/Builders/LocationHeatMapLayerBuilderAnimated.ts +0 -21
- package/src/Layers/Builders/LocationPointsMapLayerBuilder.ts +0 -17
- package/src/Layers/Builders/index.ts +0 -3
- package/src/Layers/CircleLayer.ts +0 -31
- package/src/Layers/Configs/HeatMapFillLayerConfig.ts +0 -13
- package/src/Layers/Configs/HeatMapLineLayerConfig.ts +0 -13
- package/src/Layers/Configs/HeatMapSymbolLayerConfig.ts +0 -18
- package/src/Layers/Configs/LocationPointLayerConfig.ts +0 -15
- package/src/Layers/Configs/index.ts +0 -4
- package/src/Layers/FillLayer.ts +0 -23
- package/src/Layers/LineLayer.ts +0 -24
- package/src/Layers/MapLayer.ts +0 -6
- package/src/Layers/SymbolLayer.ts +0 -23
- package/src/Layers/index.ts +0 -7
- package/src/MapBoxClasses/MapBase.ts +0 -45
- package/src/MapBoxClasses/MapHeat.ts +0 -184
- package/src/MapBoxClasses/MapPoints.ts +0 -39
- package/src/MapBoxClasses/MapSettings.ts +0 -132
- package/src/MapBoxClasses/index.ts +0 -4
- package/src/global.d.ts +0 -1
- package/src/hooks/index.ts +0 -3
- package/src/hooks/useDynamicMapResize.tsx +0 -43
- package/src/hooks/useDynamicPositioning.tsx +0 -68
- package/src/hooks/useQuadKeyPayloadsToFeatures.tsx +0 -54
- package/src/index.ts +0 -5
- package/src/lib/MapBoxBaseProps.ts +0 -20
- package/src/lib/index.ts +0 -1
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { LayerBase } from '@xylabs/geo'
|
|
2
|
-
import type { CircleLayerSpecification } from 'mapbox-gl'
|
|
3
|
-
|
|
4
|
-
export class CircleLayerBuilder extends LayerBase<CircleLayerSpecification> {
|
|
5
|
-
CircleLayerOptions: Partial<CircleLayerSpecification>
|
|
6
|
-
|
|
7
|
-
// ensures this class passes for `AnyLayer` type in MapBox
|
|
8
|
-
type: 'circle' = 'circle' as const
|
|
9
|
-
|
|
10
|
-
constructor(id: string, source: string, CircleLayerOptions?: Partial<CircleLayerSpecification>) {
|
|
11
|
-
super(id, source)
|
|
12
|
-
this.CircleLayerOptions = CircleLayerOptions || {
|
|
13
|
-
id: this.id, source: this.source, type: 'circle',
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
buildLayer(): CircleLayerSpecification {
|
|
18
|
-
return {
|
|
19
|
-
filter: ['==', '$type', 'Point'],
|
|
20
|
-
layout: {},
|
|
21
|
-
paint: {
|
|
22
|
-
'circle-color': '#ff0000',
|
|
23
|
-
'circle-radius': 6,
|
|
24
|
-
},
|
|
25
|
-
type: this.type,
|
|
26
|
-
...this.CircleLayerOptions,
|
|
27
|
-
id: this.id,
|
|
28
|
-
source: this.source,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { FillLayerSpecification } from 'mapbox-gl'
|
|
2
|
-
|
|
3
|
-
export const HeatMapFillLayerConfig: (color: string) => Partial<FillLayerSpecification> = color => ({
|
|
4
|
-
paint: {
|
|
5
|
-
'fill-color': color,
|
|
6
|
-
'fill-opacity': [
|
|
7
|
-
'let',
|
|
8
|
-
'density',
|
|
9
|
-
['+', ['/', ['number', ['get', 'value']], 4], 0.125],
|
|
10
|
-
['interpolate', ['linear'], ['var', 'density'], 0.8, ['var', 'density'], 1, 0.85],
|
|
11
|
-
],
|
|
12
|
-
},
|
|
13
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { LineLayerSpecification } from 'mapbox-gl'
|
|
2
|
-
|
|
3
|
-
export const HeatMapLineLayerConfig: (color: string) => Partial<LineLayerSpecification> = color => ({
|
|
4
|
-
layout: {
|
|
5
|
-
// Enable for debugging
|
|
6
|
-
visibility: 'none',
|
|
7
|
-
},
|
|
8
|
-
paint: {
|
|
9
|
-
'line-color': color,
|
|
10
|
-
'line-opacity': ['let', 'density', 0, ['interpolate', ['linear'], ['var', 'density'], 0.8, ['var', 'density'], 1, 0.85]],
|
|
11
|
-
'line-width': 0.5,
|
|
12
|
-
},
|
|
13
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { SymbolLayerSpecification } from 'mapbox-gl'
|
|
2
|
-
|
|
3
|
-
export const HeatMapSymbolLayerConfig: (color: string) => Partial<SymbolLayerSpecification> = color => ({
|
|
4
|
-
layout: {
|
|
5
|
-
'text-anchor': 'center',
|
|
6
|
-
'text-field': [
|
|
7
|
-
'concat',
|
|
8
|
-
'value: ',
|
|
9
|
-
['to-string', ['+', ['/', ['number', ['get', 'value']], 2], 0.25]],
|
|
10
|
-
'\n',
|
|
11
|
-
'count: ',
|
|
12
|
-
['to-string', ['get', 'count']],
|
|
13
|
-
],
|
|
14
|
-
'text-size': 10,
|
|
15
|
-
'visibility': 'none',
|
|
16
|
-
},
|
|
17
|
-
paint: { 'text-color': color },
|
|
18
|
-
})
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { CircleLayerSpecification } from 'mapbox-gl'
|
|
2
|
-
|
|
3
|
-
export const LocationPointLayerConfig: (color: string, circleRadius: number, circleOpacity: number) => Partial<CircleLayerSpecification> = (
|
|
4
|
-
color,
|
|
5
|
-
circleRadius,
|
|
6
|
-
circleOpacity,
|
|
7
|
-
) => {
|
|
8
|
-
return {
|
|
9
|
-
paint: {
|
|
10
|
-
'circle-color': color,
|
|
11
|
-
'circle-opacity': circleOpacity,
|
|
12
|
-
'circle-radius': circleRadius,
|
|
13
|
-
},
|
|
14
|
-
}
|
|
15
|
-
}
|
package/src/Layers/FillLayer.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { LayerBase } from '@xylabs/geo'
|
|
2
|
-
import type { FillLayerSpecification } from 'mapbox-gl'
|
|
3
|
-
|
|
4
|
-
export class FillLayerBuilder extends LayerBase<FillLayerSpecification> {
|
|
5
|
-
FillLayerOptions: Partial<FillLayerSpecification>
|
|
6
|
-
|
|
7
|
-
// ensures this class passes for `AnyLayer` type in MapBox
|
|
8
|
-
type: 'fill' = 'fill' as const
|
|
9
|
-
|
|
10
|
-
constructor(id: string, source: string, FillLayerOptions?: Partial<FillLayerSpecification>) {
|
|
11
|
-
super(id, source)
|
|
12
|
-
this.FillLayerOptions = FillLayerOptions || { id: this.id, source: this.source }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
buildLayer(): FillLayerSpecification {
|
|
16
|
-
return {
|
|
17
|
-
...this.FillLayerOptions,
|
|
18
|
-
id: this.id,
|
|
19
|
-
source: this.source,
|
|
20
|
-
type: this.type,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/Layers/LineLayer.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { LayerBase } from '@xylabs/geo'
|
|
2
|
-
import type { LineLayerSpecification } from 'mapbox-gl'
|
|
3
|
-
|
|
4
|
-
export class LineLayerBuilder extends LayerBase<LineLayerSpecification> {
|
|
5
|
-
LineLayerOptions: Partial<LineLayerSpecification>
|
|
6
|
-
|
|
7
|
-
// ensures this class passes for `AnyLayer` type in MapBox
|
|
8
|
-
type: 'line' = 'line' as const
|
|
9
|
-
|
|
10
|
-
constructor(id: string, source: string, LineLayerOptions?: Partial<LineLayerSpecification>) {
|
|
11
|
-
super(id, source)
|
|
12
|
-
this.LineLayerOptions = LineLayerOptions || { id: this.id, source: this.source }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
buildLayer(): LineLayerSpecification {
|
|
16
|
-
return {
|
|
17
|
-
...this.LineLayerOptions,
|
|
18
|
-
id: this.id,
|
|
19
|
-
layout: {},
|
|
20
|
-
source: this.source,
|
|
21
|
-
type: this.type,
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
package/src/Layers/MapLayer.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { LayerBase } from '@xylabs/geo'
|
|
2
|
-
import type { SymbolLayerSpecification } from 'mapbox-gl'
|
|
3
|
-
|
|
4
|
-
export class SymbolLayerBuilder extends LayerBase<SymbolLayerSpecification> {
|
|
5
|
-
SymbolLayerOptions: Partial<SymbolLayerSpecification>
|
|
6
|
-
|
|
7
|
-
// ensures this class passes for `AnyLayer` type in MapBox
|
|
8
|
-
type: 'symbol' = 'symbol' as const
|
|
9
|
-
|
|
10
|
-
constructor(id: string, source: string, SymbolLayerOptions?: Partial<SymbolLayerSpecification>) {
|
|
11
|
-
super(id, source)
|
|
12
|
-
this.SymbolLayerOptions = SymbolLayerOptions || { id: this.id, source: this.source }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
buildLayer(): SymbolLayerSpecification {
|
|
16
|
-
return {
|
|
17
|
-
...this.SymbolLayerOptions,
|
|
18
|
-
id: this.id,
|
|
19
|
-
source: this.source,
|
|
20
|
-
type: this.type,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/Layers/index.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { GeoJson } from '@xylabs/geo'
|
|
2
|
-
import { assertEx } from '@xylabs/sdk-js'
|
|
3
|
-
import type { Feature, Geometry } from 'geojson'
|
|
4
|
-
import type { GeoJSONSource, Map } from 'mapbox-gl'
|
|
5
|
-
|
|
6
|
-
import type { MapLayer } from '../Layers/index.ts'
|
|
7
|
-
|
|
8
|
-
export interface MapBaseConfig<T extends Geometry> {
|
|
9
|
-
features: Feature<T>[]
|
|
10
|
-
map: Map
|
|
11
|
-
requestLocation?: boolean
|
|
12
|
-
zoom?: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export abstract class MapBase<T extends Geometry> {
|
|
16
|
-
private _config: MapBaseConfig<T>
|
|
17
|
-
|
|
18
|
-
constructor(config: MapBaseConfig<T>) {
|
|
19
|
-
this._config = {
|
|
20
|
-
requestLocation: true, zoom: 2, ...config,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get isMapReady() {
|
|
25
|
-
return !!this._config.map
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
initializeMapSource(layer: MapLayer) {
|
|
29
|
-
const getSource = () => {
|
|
30
|
-
const featuresCollection = GeoJson.featureCollection(this._config.features)
|
|
31
|
-
return GeoJson.featuresSource(featuresCollection)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const existingSource = this._config.map.getSource(layer.source as string) as GeoJSONSource
|
|
35
|
-
const source = getSource()
|
|
36
|
-
if (existingSource) {
|
|
37
|
-
existingSource.setData(assertEx(source.data as GeoJSON.Feature<GeoJSON.Geometry> | GeoJSON.FeatureCollection<GeoJSON.Geometry>))
|
|
38
|
-
} else {
|
|
39
|
-
this._config.map.addSource(layer.source as string, source)
|
|
40
|
-
}
|
|
41
|
-
layer.update(this._config.map, true)
|
|
42
|
-
|
|
43
|
-
return this
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { GeoJson } from '@xylabs/geo'
|
|
2
|
-
import {
|
|
3
|
-
assertEx, delay, forget,
|
|
4
|
-
} from '@xylabs/sdk-js'
|
|
5
|
-
import type { Feature, Polygon } from 'geojson'
|
|
6
|
-
import type {
|
|
7
|
-
DataDrivenPropertyValueSpecification,
|
|
8
|
-
GeoJSONSource, GeoJSONSourceSpecification, Map, MapOptions,
|
|
9
|
-
} from 'mapbox-gl'
|
|
10
|
-
import { LngLatBounds } from 'mapbox-gl'
|
|
11
|
-
|
|
12
|
-
import type { MapLayer } from '../Layers/index.ts'
|
|
13
|
-
import type { MapBaseConfig } from './MapBase.ts'
|
|
14
|
-
import { MapBase } from './MapBase.ts'
|
|
15
|
-
|
|
16
|
-
export class MapHeat extends MapBase<Polygon> {
|
|
17
|
-
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
18
|
-
static animationStarted = false
|
|
19
|
-
|
|
20
|
-
config: MapBaseConfig<Polygon>
|
|
21
|
-
constructor(config: MapBaseConfig<Polygon>) {
|
|
22
|
-
super(config)
|
|
23
|
-
this.config = config
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static initialMapPositioning(options: MapOptions['fitBoundsOptions'], map: Map, features?: Feature<Polygon>[], initialBounds?: LngLatBounds) {
|
|
27
|
-
if (!features) {
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let bounds: LngLatBounds
|
|
32
|
-
|
|
33
|
-
if (initialBounds) {
|
|
34
|
-
bounds = initialBounds
|
|
35
|
-
} else {
|
|
36
|
-
bounds = new LngLatBounds()
|
|
37
|
-
|
|
38
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
39
|
-
features.forEach((feature: Feature<Polygon>) => {
|
|
40
|
-
for (const coordinates of feature.geometry.coordinates) {
|
|
41
|
-
for (const position of coordinates) {
|
|
42
|
-
bounds.extend(position as [number, number])
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
map.setCenter(bounds.getCenter())
|
|
49
|
-
map.fitBounds(bounds, options)
|
|
50
|
-
return this
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
static async initializeAnimatedHeatMapSource(
|
|
54
|
-
layers: MapLayer[],
|
|
55
|
-
featureSet: Feature<Polygon>[][],
|
|
56
|
-
map: Map,
|
|
57
|
-
startColor?: string,
|
|
58
|
-
endColor?: string,
|
|
59
|
-
) {
|
|
60
|
-
this.animationStarted = true
|
|
61
|
-
let layerTick = 0
|
|
62
|
-
let sourceTick = 0
|
|
63
|
-
|
|
64
|
-
const sources = featureSet.map((feature) => {
|
|
65
|
-
const featuresCollection = GeoJson.featureCollection(feature)
|
|
66
|
-
return GeoJson.featuresSource(featuresCollection)
|
|
67
|
-
})
|
|
68
|
-
this.updateLayer(map, layers[0], sources[0])
|
|
69
|
-
this.updateLayer(map, layers[1], sources[1])
|
|
70
|
-
|
|
71
|
-
for (const layer of layers) {
|
|
72
|
-
map.setPaintProperty(layer.id, 'fill-opacity', 0)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const frameLength = 3000
|
|
76
|
-
const initialPad = 0.5
|
|
77
|
-
const factor = 10
|
|
78
|
-
const steps = 30
|
|
79
|
-
const stepLength = frameLength / steps
|
|
80
|
-
const lowUsageColor = startColor ?? '#FFB3B3'
|
|
81
|
-
const highUsageColor = endColor ?? '#FF0000'
|
|
82
|
-
|
|
83
|
-
// Max density at i=0, min density at i=steps
|
|
84
|
-
const dynamicFillColor = (factor: number, initialPad: number, i: number): DataDrivenPropertyValueSpecification<string> => {
|
|
85
|
-
const sinFade = Math.sin(((i / steps) * Math.PI) / 2)
|
|
86
|
-
const cosFade = Math.cos(((i / steps) * Math.PI) / 2)
|
|
87
|
-
// we want the divisor to always be at least 1x the desired factor but will go up to
|
|
88
|
-
// 2x factor to account for combinative effect of the overlay of two layers at once
|
|
89
|
-
const divisor = factor + factor * sinFade
|
|
90
|
-
const offset = initialPad * cosFade
|
|
91
|
-
return [
|
|
92
|
-
'let',
|
|
93
|
-
'density',
|
|
94
|
-
['+', ['/', ['number', ['get', 'value']], divisor], offset],
|
|
95
|
-
['interpolate', ['linear'], ['var', 'density'], 0, lowUsageColor, 0.5, highUsageColor],
|
|
96
|
-
]
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const fadedIn: boolean[] = layers.map(_ => false)
|
|
100
|
-
|
|
101
|
-
const fadeIn = async (id: string, index: number) => {
|
|
102
|
-
for (let i = steps; i >= 1; i--) {
|
|
103
|
-
map.setPaintProperty(id, 'fill-color', dynamicFillColor(factor, initialPad, i * (180 / stepLength)))
|
|
104
|
-
await delay(stepLength)
|
|
105
|
-
}
|
|
106
|
-
fadedIn[index] = true
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const fadeOut = async (id: string, index: number) => {
|
|
110
|
-
for (let i = 1; i <= steps; i++) {
|
|
111
|
-
map.setPaintProperty(id, 'fill-color', dynamicFillColor(factor, initialPad, i * (180 / stepLength)))
|
|
112
|
-
await delay(stepLength)
|
|
113
|
-
}
|
|
114
|
-
fadedIn[index] = false
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
let started = false
|
|
118
|
-
const startAnimation = async () => {
|
|
119
|
-
assertEx(!started, () => 'Animation Already Started')
|
|
120
|
-
started = true
|
|
121
|
-
while (this.animationStarted) {
|
|
122
|
-
const upLayer = layerTick % layers.length
|
|
123
|
-
const downLayer = (layerTick + 1) % layers.length
|
|
124
|
-
|
|
125
|
-
const incomingSource = sourceTick % featureSet.length
|
|
126
|
-
const outgoingSource = (sourceTick + 1) % featureSet.length
|
|
127
|
-
|
|
128
|
-
// console.log('incoming / outgoing source', incomingSource, outgoingSource)
|
|
129
|
-
|
|
130
|
-
// console.log(`animate: [${upLayer}, ${downLayer}]`)
|
|
131
|
-
if (fadedIn[upLayer]) {
|
|
132
|
-
this.updateLayer(map, layers[upLayer], sources[incomingSource])
|
|
133
|
-
forget(fadeOut(layers[upLayer].id, upLayer))
|
|
134
|
-
}
|
|
135
|
-
if (!fadedIn[downLayer]) {
|
|
136
|
-
this.updateLayer(map, layers[downLayer], sources[outgoingSource])
|
|
137
|
-
forget(fadeIn(layers[downLayer].id, downLayer))
|
|
138
|
-
}
|
|
139
|
-
while ((fadedIn[upLayer] || !fadedIn[downLayer]) && this.animationStarted) {
|
|
140
|
-
// console.log(`checking: [${fadedIn[upLayer]}, ${!fadedIn[downLayer]}]`)
|
|
141
|
-
await delay(1000)
|
|
142
|
-
}
|
|
143
|
-
layerTick++
|
|
144
|
-
sourceTick++
|
|
145
|
-
|
|
146
|
-
// console.log(`this.layerTick: ${layerTick}`)
|
|
147
|
-
// console.log(`this.sourceTick: ${sourceTick}`)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
await startAnimation()
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private static updateLayer(map: Map, layer: MapLayer, source: GeoJSONSourceSpecification) {
|
|
155
|
-
const existingSource = map.getSource(layer.source as string) as GeoJSONSource
|
|
156
|
-
if (existingSource && source.data) {
|
|
157
|
-
existingSource.setData(source.data as GeoJSON.Feature<GeoJSON.Geometry> | GeoJSON.FeatureCollection<GeoJSON.Geometry>)
|
|
158
|
-
} else if (source) {
|
|
159
|
-
map.addSource(layer.source as string, source)
|
|
160
|
-
}
|
|
161
|
-
layer.update(map, true)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Build layers each with the same features
|
|
165
|
-
initializeHeatMapSource(layers: MapLayer[]) {
|
|
166
|
-
const getSource = (_: number) => {
|
|
167
|
-
const featuresCollection = GeoJson.featureCollection(this.config.features)
|
|
168
|
-
return GeoJson.featuresSource(featuresCollection)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
for (const [index, layer] of layers.entries()) {
|
|
172
|
-
const existingSource = this.config.map.getSource(layer.source as string) as GeoJSONSource
|
|
173
|
-
const source = getSource(index)
|
|
174
|
-
if (existingSource) {
|
|
175
|
-
existingSource.setData(assertEx(source.data) as GeoJSON.Feature<GeoJSON.Geometry> | GeoJSON.FeatureCollection<GeoJSON.Geometry>)
|
|
176
|
-
} else {
|
|
177
|
-
this.config.map.addSource(layer.source as string, source)
|
|
178
|
-
}
|
|
179
|
-
layer.update(this.config.map, true)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return this
|
|
183
|
-
}
|
|
184
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { Feature, Point } from 'geojson'
|
|
2
|
-
import type { MapOptions } from 'mapbox-gl'
|
|
3
|
-
import { LngLatBounds } from 'mapbox-gl'
|
|
4
|
-
|
|
5
|
-
import type { MapBaseConfig } from './MapBase.ts'
|
|
6
|
-
import { MapBase } from './MapBase.ts'
|
|
7
|
-
|
|
8
|
-
export interface MapPointsConfig extends MapBaseConfig<Point> {
|
|
9
|
-
features: Feature<Point>[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class MapPoints extends MapBase<Point> {
|
|
13
|
-
private config: MapPointsConfig
|
|
14
|
-
|
|
15
|
-
constructor(config: MapPointsConfig) {
|
|
16
|
-
super(config)
|
|
17
|
-
this.config = config
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
initialMapPositioning(options: MapOptions['fitBoundsOptions'], initialBounds?: LngLatBounds) {
|
|
21
|
-
let bounds: LngLatBounds
|
|
22
|
-
|
|
23
|
-
if (initialBounds) {
|
|
24
|
-
bounds = initialBounds
|
|
25
|
-
} else {
|
|
26
|
-
bounds = new LngLatBounds()
|
|
27
|
-
|
|
28
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
29
|
-
this.config.features.forEach((feature: Feature<Point>) => {
|
|
30
|
-
bounds.extend(feature.geometry.coordinates as [number, number])
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.config.map.setCenter(bounds.getCenter())
|
|
35
|
-
this.config.map.fitBounds(bounds, options)
|
|
36
|
-
|
|
37
|
-
return this.config.map
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import type { MapSetting } from '@xyo-network/react-map-model'
|
|
2
|
-
import type {
|
|
3
|
-
Map, MapEventOf, MapEventType,
|
|
4
|
-
} from 'mapbox-gl'
|
|
5
|
-
import { GeolocateControl, NavigationControl } from 'mapbox-gl'
|
|
6
|
-
|
|
7
|
-
export interface MapSettingsConfig {
|
|
8
|
-
debugLayerName?: string
|
|
9
|
-
map: Map
|
|
10
|
-
requestLocation?: boolean
|
|
11
|
-
settings: MapSetting
|
|
12
|
-
zoom?: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Utility class to handle changes in settings
|
|
17
|
-
*
|
|
18
|
-
* Methods are pure functions dedicated to map manipulation
|
|
19
|
-
*/
|
|
20
|
-
export class MapSettings {
|
|
21
|
-
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
22
|
-
static geoLocateControl: GeolocateControl | undefined
|
|
23
|
-
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
24
|
-
static mapListeners = {
|
|
25
|
-
logData: (ev?: MapEventOf<MapEventType>, map?: Map) => {
|
|
26
|
-
const target = map || ev?.target
|
|
27
|
-
if (target) {
|
|
28
|
-
console.log('zoom', target.getZoom())
|
|
29
|
-
console.log('center', target.getCenter())
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
35
|
-
static navControl: NavigationControl | undefined
|
|
36
|
-
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
37
|
-
static requestLocation: boolean | undefined
|
|
38
|
-
|
|
39
|
-
static toggleControls(value: boolean | undefined, map: Map, zoom?: number, requestLocation?: boolean) {
|
|
40
|
-
if (value) {
|
|
41
|
-
MapSettings.addControls(map, zoom, requestLocation)
|
|
42
|
-
} else {
|
|
43
|
-
MapSettings.removeControls(map)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return this
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
static toggleDebugLayer(value: boolean | undefined, map: Map, layerName: string) {
|
|
50
|
-
const debugLayer = map.getLayer(layerName)
|
|
51
|
-
if (debugLayer) {
|
|
52
|
-
if (value) {
|
|
53
|
-
map.setLayoutProperty(layerName, 'visibility', 'visible')
|
|
54
|
-
} else {
|
|
55
|
-
map.setLayoutProperty(layerName, 'visibility', 'none')
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return this
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
static toggleDebugLogging(value: boolean | undefined, map: Map) {
|
|
63
|
-
const debugEvents: MapEventType[] = ['resize', 'zoomend', 'dragend']
|
|
64
|
-
if (value) {
|
|
65
|
-
// initial values
|
|
66
|
-
this.mapListeners.logData(undefined, map)
|
|
67
|
-
for (const event of debugEvents) map.on(event, this.mapListeners.logData)
|
|
68
|
-
} else {
|
|
69
|
-
for (const event of debugEvents) map.off(event, this.mapListeners.logData)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
static toggleScrollToZoom(value: boolean | undefined, map: Map) {
|
|
74
|
-
if (value) {
|
|
75
|
-
map.scrollZoom.enable()
|
|
76
|
-
} else {
|
|
77
|
-
map.scrollZoom.disable()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return this
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static updateSettings(config: MapSettingsConfig) {
|
|
84
|
-
const {
|
|
85
|
-
settings, map, zoom, requestLocation, debugLayerName = '',
|
|
86
|
-
} = config
|
|
87
|
-
const {
|
|
88
|
-
scrollToZoom, enableControls, debugLayer, debugLogging,
|
|
89
|
-
} = settings
|
|
90
|
-
|
|
91
|
-
MapSettings.toggleControls(enableControls?.value, map, zoom, requestLocation)
|
|
92
|
-
.toggleScrollToZoom(scrollToZoom?.value, map)
|
|
93
|
-
.toggleDebugLayer(debugLayer?.value, map, debugLayerName)
|
|
94
|
-
.toggleDebugLogging(debugLogging.value, map)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Needs to be static so we ensure controls are only instantiated once
|
|
98
|
-
private static addControls(map: Map, zoom?: number, requestLocation?: boolean) {
|
|
99
|
-
const geolocateControl = new GeolocateControl({
|
|
100
|
-
fitBoundsOptions: { zoom: zoom || 2 },
|
|
101
|
-
positionOptions: { enableHighAccuracy: true },
|
|
102
|
-
trackUserLocation: true,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const navControl = new NavigationControl({ showCompass: false })
|
|
106
|
-
|
|
107
|
-
this.geoLocateControl = this.geoLocateControl || geolocateControl
|
|
108
|
-
this.navControl = this.navControl || navControl
|
|
109
|
-
|
|
110
|
-
if (!map.hasControl(this.geoLocateControl) && requestLocation) {
|
|
111
|
-
map.addControl(this.geoLocateControl)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!map.hasControl(this.navControl)) {
|
|
115
|
-
map.addControl(this.navControl, 'top-left')
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return this
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private static removeControls(map: Map) {
|
|
122
|
-
if (this.geoLocateControl && map.hasControl(this.geoLocateControl) && this.requestLocation) {
|
|
123
|
-
map.removeControl(this.geoLocateControl)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (this.navControl && map.hasControl(this.navControl)) {
|
|
127
|
-
map.removeControl(this.navControl)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return this
|
|
131
|
-
}
|
|
132
|
-
}
|
package/src/global.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@mui/material/themeCssVarsAugmentation'
|
package/src/hooks/index.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { Map } from 'mapbox-gl'
|
|
2
|
-
import type { RefObject } from 'react'
|
|
3
|
-
import { useEffect, useMemo } from 'react'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Inspired by - https://bl.ocks.org/danswick/fc56f37c10d40be62e4feac5984250d2
|
|
7
|
-
*/
|
|
8
|
-
export const useDynamicMapResize = (
|
|
9
|
-
mapContainerRef: RefObject<HTMLDivElement | null>,
|
|
10
|
-
mapCanvasRef: RefObject<HTMLCanvasElement | null>,
|
|
11
|
-
mapInstance?: Map,
|
|
12
|
-
active = true,
|
|
13
|
-
) => {
|
|
14
|
-
const resizer = useMemo(
|
|
15
|
-
() =>
|
|
16
|
-
new ResizeObserver(() => {
|
|
17
|
-
const width = mapContainerRef.current?.getBoundingClientRect().width
|
|
18
|
-
if (width && mapCanvasRef.current) {
|
|
19
|
-
mapCanvasRef.current.style.width = `${width}px`
|
|
20
|
-
// setTimeout allows for the smoothest animation (vs requestAnimationFrame, debouce, etc)
|
|
21
|
-
// likely because it lets mapbox resize once when the event loop is ready?
|
|
22
|
-
setTimeout(() => mapInstance?.resize())
|
|
23
|
-
}
|
|
24
|
-
}),
|
|
25
|
-
[mapCanvasRef, mapContainerRef, mapInstance],
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
const dependenciesReady = useMemo(() => {
|
|
29
|
-
return !!(active && mapInstance && mapContainerRef?.current && mapCanvasRef.current)
|
|
30
|
-
}, [active, mapCanvasRef, mapContainerRef, mapInstance])
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (dependenciesReady) {
|
|
34
|
-
if (mapContainerRef.current) {
|
|
35
|
-
resizer.observe(mapContainerRef.current)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return () => {
|
|
39
|
-
resizer.disconnect()
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}, [active, dependenciesReady, mapCanvasRef, mapContainerRef, mapInstance, resizer])
|
|
43
|
-
}
|