@versatiles/svelte 1.0.1 → 1.1.0

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.
Files changed (81) hide show
  1. package/dist/components/BBoxMap/AutoComplete.svelte +117 -90
  2. package/dist/components/BBoxMap/BBoxMap.svelte +49 -40
  3. package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +0 -1
  4. package/dist/components/BasicMap/BasicMap.svelte +60 -34
  5. package/dist/components/LocatorMap/LocatorMap.svelte +66 -60
  6. package/dist/components/LocatorMap/LocatorMap.svelte.d.ts +0 -1
  7. package/dist/components/MapEditor/MapEditor.svelte +34 -80
  8. package/dist/components/MapEditor/MapEditor.svelte.d.ts +0 -1
  9. package/dist/components/MapEditor/components/Editor.svelte +53 -0
  10. package/dist/components/MapEditor/{Editor.svelte.d.ts → components/Editor.svelte.d.ts} +1 -1
  11. package/dist/components/MapEditor/components/EditorFill.svelte +28 -0
  12. package/dist/components/MapEditor/components/EditorFill.svelte.d.ts +7 -0
  13. package/dist/components/MapEditor/components/EditorStroke.svelte +28 -0
  14. package/dist/components/MapEditor/components/EditorStroke.svelte.d.ts +7 -0
  15. package/dist/components/MapEditor/components/EditorSymbol.svelte +43 -0
  16. package/dist/components/MapEditor/components/EditorSymbol.svelte.d.ts +7 -0
  17. package/dist/components/MapEditor/components/Sidebar.svelte +179 -0
  18. package/dist/components/MapEditor/components/Sidebar.svelte.d.ts +8 -0
  19. package/dist/components/MapEditor/components/SymbolSelector.svelte +118 -0
  20. package/dist/components/MapEditor/components/SymbolSelector.svelte.d.ts +8 -0
  21. package/dist/components/MapEditor/lib/__mocks__/cursor.d.ts +5 -0
  22. package/dist/components/MapEditor/lib/__mocks__/cursor.js +6 -0
  23. package/dist/components/MapEditor/lib/__mocks__/geometry_manager.d.ts +22 -0
  24. package/dist/components/MapEditor/lib/__mocks__/geometry_manager.js +21 -0
  25. package/dist/components/MapEditor/lib/__mocks__/map.d.ts +36 -0
  26. package/dist/components/MapEditor/lib/__mocks__/map.js +26 -0
  27. package/dist/components/MapEditor/lib/cursor.d.ts +10 -0
  28. package/dist/components/MapEditor/lib/cursor.js +43 -0
  29. package/dist/components/MapEditor/lib/element/abstract.d.ts +21 -0
  30. package/dist/components/MapEditor/lib/element/abstract.js +39 -0
  31. package/dist/components/MapEditor/lib/element/abstract_path.d.ts +11 -0
  32. package/dist/components/MapEditor/lib/element/abstract_path.js +79 -0
  33. package/dist/components/MapEditor/lib/element/line.d.ts +16 -0
  34. package/dist/components/MapEditor/lib/element/line.js +53 -0
  35. package/dist/components/MapEditor/lib/element/marker.d.ts +18 -0
  36. package/dist/components/MapEditor/lib/element/marker.js +62 -0
  37. package/dist/components/MapEditor/lib/element/polygon.d.ts +17 -0
  38. package/dist/components/MapEditor/lib/element/polygon.js +63 -0
  39. package/dist/components/MapEditor/lib/element/types.d.ts +11 -0
  40. package/dist/components/MapEditor/lib/geometry_manager.d.ts +20 -10
  41. package/dist/components/MapEditor/lib/geometry_manager.js +163 -57
  42. package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +30 -0
  43. package/dist/components/MapEditor/lib/map_layer/abstract.js +94 -0
  44. package/dist/components/MapEditor/lib/map_layer/fill.d.ts +24 -0
  45. package/dist/components/MapEditor/lib/map_layer/fill.js +104 -0
  46. package/dist/components/MapEditor/lib/map_layer/line.d.ts +20 -0
  47. package/dist/components/MapEditor/lib/map_layer/line.js +90 -0
  48. package/dist/components/MapEditor/lib/map_layer/symbol.d.ts +19 -0
  49. package/dist/components/MapEditor/lib/map_layer/symbol.js +123 -0
  50. package/dist/components/MapEditor/lib/{types.d.ts → map_layer/types.d.ts} +7 -15
  51. package/dist/components/MapEditor/lib/map_layer/types.js +1 -0
  52. package/dist/components/MapEditor/lib/state/reader.d.ts +17 -0
  53. package/dist/components/MapEditor/lib/state/reader.js +161 -0
  54. package/dist/components/MapEditor/lib/state/types.d.ts +20 -0
  55. package/dist/components/MapEditor/lib/state/types.js +1 -0
  56. package/dist/components/MapEditor/lib/state/writer.d.ts +17 -0
  57. package/dist/components/MapEditor/lib/state/writer.js +178 -0
  58. package/dist/components/MapEditor/lib/symbols.d.ts +16 -0
  59. package/dist/components/MapEditor/lib/symbols.js +173 -0
  60. package/dist/components/MapEditor/lib/utils.d.ts +8 -1
  61. package/dist/components/MapEditor/lib/utils.js +33 -2
  62. package/dist/utils/draw/bbox.d.ts +1 -0
  63. package/dist/utils/draw/bbox.js +1 -1
  64. package/package.json +29 -30
  65. package/dist/components/MapEditor/Editor.svelte +0 -25
  66. package/dist/components/MapEditor/EditorLine.svelte +0 -27
  67. package/dist/components/MapEditor/EditorLine.svelte.d.ts +0 -7
  68. package/dist/components/MapEditor/EditorMarker.svelte +0 -42
  69. package/dist/components/MapEditor/EditorMarker.svelte.d.ts +0 -7
  70. package/dist/components/MapEditor/editor.scss +0 -16
  71. package/dist/components/MapEditor/lib/element_abstract.d.ts +0 -20
  72. package/dist/components/MapEditor/lib/element_abstract.js +0 -58
  73. package/dist/components/MapEditor/lib/element_line.d.ts +0 -14
  74. package/dist/components/MapEditor/lib/element_line.js +0 -76
  75. package/dist/components/MapEditor/lib/element_marker.d.ts +0 -20
  76. package/dist/components/MapEditor/lib/element_marker.js +0 -191
  77. package/dist/components/MapEditor/lib/map_layer.d.ts +0 -14
  78. package/dist/components/MapEditor/lib/map_layer.js +0 -61
  79. package/dist/utils/sprite_library.d.ts +0 -19
  80. package/dist/utils/sprite_library.js +0 -30
  81. /package/dist/components/MapEditor/lib/{types.js → element/types.js} +0 -0
@@ -1,21 +1,30 @@
1
1
  import { get, writable } from 'svelte/store';
2
- import { MarkerElement } from './element_marker.js';
3
- import { LineElement } from './element_line.js';
2
+ import { MarkerElement } from './element/marker.js';
3
+ import { LineElement } from './element/line.js';
4
+ import { PolygonElement } from './element/polygon.js';
5
+ import { Cursor } from './cursor.js';
6
+ import { StateWriter } from './state/writer.js';
7
+ import { StateReader } from './state/reader.js';
8
+ import { SymbolLibrary } from './symbols.js';
4
9
  export class GeometryManager {
5
10
  elements;
6
11
  map;
7
- activeElement = writable(undefined);
8
- selection_nodes;
12
+ selectedElement = writable(undefined);
9
13
  canvas;
14
+ cursor;
15
+ symbolLibrary;
16
+ selectionNodes;
10
17
  constructor(map) {
11
18
  this.elements = writable([]);
12
19
  this.map = map;
13
20
  this.canvas = this.map.getCanvasContainer();
21
+ this.cursor = new Cursor(this.canvas);
22
+ this.symbolLibrary = new SymbolLibrary(map);
14
23
  map.addSource('selection_nodes', {
15
24
  type: 'geojson',
16
25
  data: { type: 'FeatureCollection', features: [] }
17
26
  });
18
- this.selection_nodes = map.getSource('selection_nodes');
27
+ this.selectionNodes = map.getSource('selection_nodes');
19
28
  map.addLayer({
20
29
  id: 'selection_nodes',
21
30
  source: 'selection_nodes',
@@ -24,54 +33,66 @@ export class GeometryManager {
24
33
  paint: {
25
34
  'circle-color': '#ffffff',
26
35
  'circle-opacity': ['get', 'opacity'],
27
- 'circle-radius': 4,
36
+ 'circle-radius': 3,
28
37
  'circle-stroke-color': '#000000',
29
38
  'circle-stroke-opacity': ['get', 'opacity'],
30
- 'circle-stroke-width': 1.5
39
+ 'circle-stroke-width': 1
31
40
  }
32
41
  });
33
42
  map.on('mousedown', 'selection_nodes', (e) => {
34
- const element = get(this.activeElement);
43
+ const element = get(this.selectedElement);
35
44
  if (element == undefined)
36
45
  return;
37
46
  const feature = map.queryRenderedFeatures(e.point, { layers: ['selection_nodes'] })[0];
38
- const updateSelectionNode = element.getSelectionNodeUpdater(feature.properties);
39
- if (updateSelectionNode == undefined)
47
+ const selectedNode = element.getSelectionNodeUpdater(feature.properties);
48
+ if (selectedNode == undefined)
40
49
  return;
50
+ // @ts-expect-error ensure that the event is ignored by other layers
51
+ e.ignore = true;
41
52
  e.preventDefault();
42
- const onMove = (e) => {
43
- e.preventDefault();
44
- this.canvas.style.cursor = 'grabbing';
45
- updateSelectionNode(e.lngLat.lng, e.lngLat.lat);
46
- this.drawSelectionNodes(element.getSelectionNodes());
47
- };
48
- const onUp = () => {
49
- map.off('mousemove', onMove);
50
- this.canvas.style.cursor = 'default';
51
- };
52
- map.once('mouseup', onUp);
53
- map.on('mousemove', onMove);
53
+ if (e.originalEvent.shiftKey) {
54
+ selectedNode.delete();
55
+ this.drawSelectionNodes();
56
+ this.saveState();
57
+ }
58
+ else {
59
+ const onMove = (e) => {
60
+ e.preventDefault();
61
+ selectedNode.update(e.lngLat.lng, e.lngLat.lat);
62
+ this.drawSelectionNodes();
63
+ };
64
+ map.on('mousemove', onMove);
65
+ map.once('mouseup', () => {
66
+ this.saveState();
67
+ map.off('mousemove', onMove);
68
+ });
69
+ }
70
+ });
71
+ map.on('mouseenter', 'selection_nodes', () => {
72
+ this.cursor.togglePrecise('selection_nodes');
73
+ });
74
+ map.on('mouseleave', 'selection_nodes', () => {
75
+ this.cursor.togglePrecise('selection_nodes', false);
54
76
  });
55
- map.on('mouseover', 'selection_nodes', () => (this.canvas.style.cursor = 'move'));
56
- map.on('mouseout', 'selection_nodes', () => (this.canvas.style.cursor = 'default'));
57
77
  map.on('click', (e) => {
58
- this.setActiveElement(undefined);
78
+ if (!e.originalEvent.shiftKey)
79
+ this.selectElement(undefined);
59
80
  e.preventDefault();
60
81
  });
82
+ map.on('moveend', () => this.saveState());
83
+ const hash = location.hash.slice(1);
84
+ if (hash)
85
+ this.loadState(hash);
61
86
  }
62
- setActiveElement(element) {
63
- if (element) {
64
- if (!get(this.elements).includes(element))
65
- throw new Error('Element not in list');
66
- this.drawSelectionNodes(element.getSelectionNodes());
67
- }
68
- else {
69
- this.drawSelectionNodes([]);
70
- }
71
- this.activeElement.set(element);
87
+ selectElement(element) {
88
+ const elements = get(this.elements);
89
+ elements.forEach((e) => e.select(e == element));
90
+ this.selectedElement.set(element);
91
+ this.drawSelectionNodes();
72
92
  }
73
- drawSelectionNodes(nodes) {
74
- this.selection_nodes.setData({
93
+ drawSelectionNodes() {
94
+ const nodes = get(this.selectedElement)?.getSelectionNodes() ?? [];
95
+ this.selectionNodes.setData({
75
96
  type: 'FeatureCollection',
76
97
  features: nodes.map((n) => ({
77
98
  type: 'Feature',
@@ -80,38 +101,123 @@ export class GeometryManager {
80
101
  }))
81
102
  });
82
103
  }
104
+ getState() {
105
+ const center = this.map.getCenter();
106
+ return {
107
+ map: {
108
+ point: [center.lng, center.lat],
109
+ zoom: this.map.getZoom()
110
+ },
111
+ elements: get(this.elements).map((element) => element.getState())
112
+ };
113
+ }
114
+ async saveState() {
115
+ const writer = new StateWriter();
116
+ writer.writeObject(this.getState());
117
+ location.hash = await writer.getBase64compressed();
118
+ }
119
+ async loadState(hash) {
120
+ if (!hash)
121
+ return;
122
+ try {
123
+ const reader = await StateReader.fromBase64compressed(hash);
124
+ const state = reader.readObject();
125
+ if (!state)
126
+ return;
127
+ if (state.map?.zoom)
128
+ this.map.setZoom(state.map.zoom);
129
+ if (state.map?.point) {
130
+ this.map.setCenter({ lng: state.map.point[0], lat: state.map.point[1] });
131
+ }
132
+ if (state.elements) {
133
+ const elements = state.elements.map((element) => {
134
+ switch (element.type) {
135
+ case 'marker':
136
+ return MarkerElement.fromState(this, element);
137
+ case 'line':
138
+ return LineElement.fromState(this, element);
139
+ case 'polygon':
140
+ return PolygonElement.fromState(this, element);
141
+ default:
142
+ throw new Error('Unknown element type');
143
+ }
144
+ });
145
+ this.elements.set(elements);
146
+ }
147
+ }
148
+ catch (error) {
149
+ console.error(error);
150
+ }
151
+ }
83
152
  getElement(index) {
84
153
  return get(this.elements)[index];
85
154
  }
86
- getNewMarker() {
87
- const element = new MarkerElement(this, this.newName('Marker '));
155
+ addNewMarker() {
156
+ const element = new MarkerElement(this);
88
157
  this.addElement(element);
89
158
  return element;
90
159
  }
91
- getNewLine() {
92
- const element = new LineElement(this, this.newName('Line '));
160
+ addNewLine() {
161
+ const element = new LineElement(this);
162
+ this.addElement(element);
163
+ return element;
164
+ }
165
+ addNewPolygon() {
166
+ const element = new PolygonElement(this);
93
167
  this.addElement(element);
94
168
  return element;
95
169
  }
96
170
  addElement(element) {
97
171
  this.elements.update((elements) => [...elements, element]);
172
+ this.saveState();
98
173
  }
99
- newName(prefix) {
100
- const set = new Set();
101
- const elements = get(this.elements);
102
- elements.forEach((e) => {
103
- const name = e.name;
104
- if (!name.startsWith(prefix))
105
- return;
106
- const index = name.substring(prefix.length);
107
- if (!/^[0-9]+/.test(index))
108
- return;
109
- set.add(parseInt(index, 10));
110
- });
111
- for (let i = 1; i <= elements.length + 1; i++) {
112
- if (!set.has(i))
113
- return prefix + i;
174
+ deleteElement(element) {
175
+ this.elements.update((elements) => elements.filter((e) => e !== element));
176
+ if (get(this.selectedElement) === element)
177
+ this.selectElement(undefined);
178
+ this.saveState();
179
+ }
180
+ getGeoJSON() {
181
+ const center = this.map.getCenter();
182
+ return {
183
+ type: 'FeatureCollection',
184
+ map: {
185
+ center: [center.lng, center.lat],
186
+ zoom: this.map.getZoom()
187
+ },
188
+ features: get(this.elements).map((element) => element.getFeature(true))
189
+ };
190
+ }
191
+ addGeoJSON(geojson) {
192
+ if ('map' in geojson) {
193
+ const { map } = geojson;
194
+ if (typeof map.zoom === 'number') {
195
+ this.map.setZoom(map.zoom);
196
+ }
197
+ if (Array.isArray(map.center)) {
198
+ const [lng, lat] = map.center;
199
+ if (typeof lng === 'number' && typeof lat === 'number') {
200
+ this.map.setCenter({ lng, lat });
201
+ }
202
+ }
203
+ }
204
+ for (const feature of geojson.features) {
205
+ let element;
206
+ switch (feature.geometry.type) {
207
+ case 'Point':
208
+ element = MarkerElement.fromGeoJSON(this, feature);
209
+ break;
210
+ case 'LineString':
211
+ element = LineElement.fromGeoJSON(this, feature);
212
+ break;
213
+ case 'Polygon':
214
+ element = PolygonElement.fromGeoJSON(this, feature);
215
+ break;
216
+ default:
217
+ throw new Error(`Unknown geometry type "${feature.geometry.type}"`);
218
+ }
219
+ this.addElement(element);
114
220
  }
115
- throw new Error('Unreachable');
221
+ this.saveState();
116
222
  }
117
223
  }
@@ -0,0 +1,30 @@
1
+ import type { LayerFill, LayerLine, LayerSymbol } from './types.js';
2
+ import type { GeometryManager } from '../geometry_manager.js';
3
+ import type { StateObject } from '../state/types.js';
4
+ type LayerSpec = LayerFill | LayerLine | LayerSymbol;
5
+ type Events = 'click' | 'mousedown' | 'mousemove' | 'mouseup';
6
+ type MouseEventHandler = (event: maplibregl.MapMouseEvent) => void;
7
+ export declare abstract class MapLayer<T extends LayerSpec> {
8
+ private layout;
9
+ private paint;
10
+ protected readonly id: string;
11
+ readonly manager: GeometryManager;
12
+ protected readonly map: maplibregl.Map;
13
+ eventHandlers: Map<Events, MouseEventHandler[]>;
14
+ isSelected: boolean;
15
+ constructor(manager: GeometryManager, id: string);
16
+ addLayer(source: string, type: 'symbol' | 'line' | 'fill', layout: T['layout'], paint: T['paint']): void;
17
+ on(event: Events, handler: MouseEventHandler): void;
18
+ off(event: Events, handler: MouseEventHandler): void;
19
+ private dispatchEvent;
20
+ private addEvents;
21
+ setPaint(paint: T['paint']): void;
22
+ updatePaint<K extends keyof T['paint'], V extends T['paint'][K]>(key: K, value: V): void;
23
+ setLayout(layout: T['layout']): void;
24
+ updateLayout<K extends keyof T['layout'], V extends T['layout'][K]>(key: K, value: V): void;
25
+ destroy(): void;
26
+ abstract getState(): StateObject | undefined;
27
+ abstract getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
28
+ abstract setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
29
+ }
30
+ export {};
@@ -0,0 +1,94 @@
1
+ import { Color } from '@versatiles/style';
2
+ export class MapLayer {
3
+ layout = {};
4
+ paint = {};
5
+ id;
6
+ manager;
7
+ map;
8
+ eventHandlers = new Map();
9
+ isSelected = false;
10
+ constructor(manager, id) {
11
+ this.manager = manager;
12
+ this.map = manager.map;
13
+ this.id = id;
14
+ }
15
+ addLayer(source, type, layout, paint) {
16
+ this.layout = layout;
17
+ this.paint = paint;
18
+ this.map.addLayer({ id: this.id, source, type, layout, paint }, 'selection_nodes');
19
+ this.addEvents();
20
+ }
21
+ on(event, handler) {
22
+ if (!this.eventHandlers.has(event))
23
+ this.eventHandlers.set(event, []);
24
+ this.eventHandlers.get(event).push(handler);
25
+ }
26
+ off(event, handler) {
27
+ if (!this.eventHandlers.has(event))
28
+ return;
29
+ const handlers = this.eventHandlers.get(event);
30
+ this.eventHandlers.set(event, handlers.filter((h) => h !== handler));
31
+ }
32
+ dispatchEvent(event, e) {
33
+ const handlers = this.eventHandlers.get(event);
34
+ if (handlers)
35
+ handlers.forEach((handler) => handler(e));
36
+ }
37
+ addEvents() {
38
+ this.map.on('mouseenter', this.id, () => {
39
+ if (this.isSelected)
40
+ this.manager.cursor.toggleGrab(this.id);
41
+ this.manager.cursor.toggleHover(this.id);
42
+ });
43
+ this.map.on('mouseleave', this.id, () => {
44
+ if (this.isSelected)
45
+ this.manager.cursor.toggleGrab(this.id, false);
46
+ this.manager.cursor.toggleHover(this.id, false);
47
+ });
48
+ this.map.on('click', this.id, (e) => {
49
+ this.dispatchEvent('click', e);
50
+ if (this.isSelected)
51
+ this.manager.cursor.toggleGrab(this.id);
52
+ this.manager.cursor.toggleHover(this.id);
53
+ e.preventDefault();
54
+ });
55
+ this.map.on('mousedown', this.id, (e) => {
56
+ if (this.manager.cursor.isPrecise())
57
+ return;
58
+ this.dispatchEvent('mousedown', e);
59
+ });
60
+ this.map.on('mouseup', this.id, (e) => this.dispatchEvent('mouseup', e));
61
+ this.map.on('mousemove', this.id, (e) => this.dispatchEvent('mousemove', e));
62
+ }
63
+ setPaint(paint) {
64
+ if (paint === undefined)
65
+ return;
66
+ const keys = new Set(Object.keys(paint).concat(Object.keys(this.paint)));
67
+ for (const key of keys.values())
68
+ this.updatePaint(key, paint[key]);
69
+ }
70
+ updatePaint(key, value) {
71
+ if (value instanceof Color)
72
+ value = value.asString();
73
+ if (this.paint[key] == value)
74
+ return;
75
+ this.map.setPaintProperty(this.id, key, value);
76
+ this.paint[key] = value;
77
+ }
78
+ setLayout(layout) {
79
+ if (layout === undefined)
80
+ return;
81
+ const keys = new Set(Object.keys(layout).concat(Object.keys(this.layout)));
82
+ for (const key of keys.values())
83
+ this.updateLayout(key, layout[key]);
84
+ }
85
+ updateLayout(key, value) {
86
+ if (this.layout[key] == value)
87
+ return;
88
+ this.map.setLayoutProperty(this.id, key, value);
89
+ this.layout[key] = value;
90
+ }
91
+ destroy() {
92
+ this.map.removeLayer(this.id);
93
+ }
94
+ }
@@ -0,0 +1,24 @@
1
+ import type { LayerFill } from './types.js';
2
+ import { MapLayer } from './abstract.js';
3
+ import type { GeometryManager } from '../geometry_manager.js';
4
+ import type { StateObject } from '../state/types.js';
5
+ interface Fill {
6
+ xf: number;
7
+ yf: number;
8
+ pattern: string;
9
+ }
10
+ export declare const fillPatterns: Map<number, {
11
+ name: string;
12
+ fill: Fill | undefined;
13
+ }>;
14
+ export declare class MapLayerFill extends MapLayer<LayerFill> {
15
+ color: import("svelte/store").Writable<string>;
16
+ opacity: import("svelte/store").Writable<number>;
17
+ pattern: import("svelte/store").Writable<number>;
18
+ constructor(manager: GeometryManager, id: string, source: string);
19
+ getState(): StateObject | undefined;
20
+ setState(state: StateObject): void;
21
+ getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
22
+ setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
23
+ }
24
+ export {};
@@ -0,0 +1,104 @@
1
+ import { get, writable } from 'svelte/store';
2
+ import { MapLayer } from './abstract.js';
3
+ import { Color } from '@versatiles/style';
4
+ import { removeDefaultFields } from '../utils.js';
5
+ const size = 32;
6
+ export const fillPatterns = new Map([
7
+ [0, { name: 'solid', fill: undefined }],
8
+ [1, { name: 'diagonal', fill: { xf: 1, yf: 1, pattern: '00002552' } }],
9
+ [2, { name: 'diagonal-thin', fill: { xf: 1, yf: 1, pattern: '0252' } }]
10
+ ]);
11
+ export class MapLayerFill extends MapLayer {
12
+ color = writable('#ff0000');
13
+ opacity = writable(1);
14
+ pattern = writable(0);
15
+ constructor(manager, id, source) {
16
+ super(manager, id);
17
+ this.addLayer(source, 'fill', {}, {
18
+ 'fill-color': Color.parse(get(this.color)).asHex(),
19
+ 'fill-opacity': get(this.opacity)
20
+ });
21
+ const updatePattern = () => {
22
+ const fill = fillPatterns.get(get(this.pattern))?.fill ?? undefined;
23
+ const color = Color.parse(get(this.color));
24
+ if (fill == null) {
25
+ this.updatePaint('fill-color', color);
26
+ this.updatePaint('fill-pattern', undefined);
27
+ return;
28
+ }
29
+ const { xf, yf, pattern: p } = fill;
30
+ const alpha = p.split('').map((c) => parseInt(c, 10) * 51);
31
+ const length = alpha.length;
32
+ const data = new Uint8ClampedArray(size * size * 4);
33
+ const c = color.asRGB().asArray();
34
+ for (let y = 0; y < size; y++) {
35
+ for (let x = 0; x < size; x++) {
36
+ const v = x * xf + y * yf;
37
+ const i = (y * size + x) * 4;
38
+ data[i] = c[0];
39
+ data[i + 1] = c[1];
40
+ data[i + 2] = c[2];
41
+ data[i + 3] = alpha[v % length];
42
+ }
43
+ }
44
+ const name = 'fill-pattern-' + this.id;
45
+ if (this.map.hasImage(name))
46
+ this.map.removeImage(name);
47
+ this.map.addImage(name, { width: size, height: size, data });
48
+ this.updatePaint('fill-pattern', name);
49
+ };
50
+ this.color.subscribe(() => {
51
+ updatePattern();
52
+ this.manager.saveState();
53
+ });
54
+ this.pattern.subscribe(() => {
55
+ updatePattern();
56
+ this.manager.saveState();
57
+ });
58
+ this.opacity.subscribe((value) => {
59
+ this.updatePaint('fill-opacity', value);
60
+ this.manager.saveState();
61
+ });
62
+ }
63
+ getState() {
64
+ return removeDefaultFields({
65
+ color: get(this.color),
66
+ opacity: get(this.opacity),
67
+ pattern: get(this.pattern)
68
+ }, {
69
+ color: '#ff0000',
70
+ opacity: 1,
71
+ pattern: 0
72
+ });
73
+ }
74
+ setState(state) {
75
+ if (state.color)
76
+ this.color.set(state.color);
77
+ if (state.opacity)
78
+ this.opacity.set(state.opacity);
79
+ if (state.pattern)
80
+ this.pattern.set(state.pattern);
81
+ }
82
+ getGeoJSONProperties() {
83
+ return {
84
+ 'fill-color': get(this.color),
85
+ 'fill-opacity': get(this.opacity),
86
+ 'fill-pattern': fillPatterns.get(get(this.pattern))?.name
87
+ };
88
+ }
89
+ setGeoJSONProperties(properties) {
90
+ if (properties == null)
91
+ return;
92
+ if (properties['fill-color'])
93
+ this.color.set(properties['fill-color']);
94
+ if (properties['fill-opacity'])
95
+ this.opacity.set(properties['fill-opacity']);
96
+ if (properties['fill-pattern']) {
97
+ const pattern = fillPatterns
98
+ .entries()
99
+ .find(([, { name }]) => name === properties['fill-pattern']);
100
+ if (pattern)
101
+ this.pattern.set(pattern[0]);
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,20 @@
1
+ import type { LayerLine } from './types.js';
2
+ import { MapLayer } from './abstract.js';
3
+ import type { GeometryManager } from '../geometry_manager.js';
4
+ import type { StateObject } from '../state/types.js';
5
+ export declare const dashArrays: Map<number, {
6
+ name: string;
7
+ array: number[] | undefined;
8
+ }>;
9
+ export declare class MapLayerLine extends MapLayer<LayerLine> {
10
+ color: import("svelte/store").Writable<string>;
11
+ dashed: import("svelte/store").Writable<number>;
12
+ visible: import("svelte/store").Writable<boolean>;
13
+ width: import("svelte/store").Writable<number>;
14
+ dashArray: import("svelte/store").Readable<number[]>;
15
+ constructor(manager: GeometryManager, id: string, source: string);
16
+ getState(): StateObject | undefined;
17
+ setState(state: StateObject): void;
18
+ getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
19
+ setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
20
+ }
@@ -0,0 +1,90 @@
1
+ import { derived, get, writable } from 'svelte/store';
2
+ import { MapLayer } from './abstract.js';
3
+ import { Color } from '@versatiles/style';
4
+ import { removeDefaultFields } from '../utils.js';
5
+ export const dashArrays = new Map([
6
+ [0, { name: 'solid', array: [100] }],
7
+ [1, { name: 'dashed', array: [2, 4] }],
8
+ [2, { name: 'dotted', array: [0, 2] }]
9
+ ]);
10
+ export class MapLayerLine extends MapLayer {
11
+ color = writable('#ff0000');
12
+ dashed = writable(0);
13
+ visible = writable(true);
14
+ width = writable(2);
15
+ dashArray = derived(this.dashed, (dashed) => dashArrays.get(dashed)?.array ?? [100]);
16
+ constructor(manager, id, source) {
17
+ super(manager, id);
18
+ this.addLayer(source, 'line', {
19
+ 'line-cap': 'round',
20
+ 'line-join': 'round',
21
+ visibility: get(this.visible) ? 'visible' : 'none'
22
+ }, {
23
+ 'line-color': Color.parse(get(this.color)).asHex(),
24
+ 'line-dasharray': get(this.dashArray),
25
+ 'line-width': get(this.width)
26
+ });
27
+ this.color.subscribe((v) => {
28
+ this.updatePaint('line-color', Color.parse(v));
29
+ this.manager.saveState();
30
+ });
31
+ this.dashArray.subscribe((v) => {
32
+ this.updatePaint('line-dasharray', v);
33
+ this.manager.saveState();
34
+ });
35
+ this.visible.subscribe((v) => {
36
+ this.updateLayout('visibility', v ? 'visible' : 'none');
37
+ this.manager.saveState();
38
+ });
39
+ this.width.subscribe((v) => {
40
+ this.updatePaint('line-width', v);
41
+ this.manager.saveState();
42
+ });
43
+ }
44
+ getState() {
45
+ return removeDefaultFields({
46
+ color: get(this.color),
47
+ pattern: get(this.dashed),
48
+ visible: get(this.visible),
49
+ width: get(this.width)
50
+ }, {
51
+ color: '#ff0000',
52
+ pattern: 0,
53
+ visible: true,
54
+ width: 2
55
+ });
56
+ }
57
+ setState(state) {
58
+ if (state.color)
59
+ this.color.set(state.color);
60
+ if (state.pattern)
61
+ this.dashed.set(state.pattern);
62
+ if (state.visible)
63
+ this.visible.set(state.visible);
64
+ if (state.width)
65
+ this.width.set(state.width);
66
+ }
67
+ getGeoJSONProperties() {
68
+ return {
69
+ 'stroke-color': get(this.color),
70
+ 'stroke-style': dashArrays.get(get(this.dashed))?.name,
71
+ 'stroke-width': get(this.width),
72
+ 'stroke-visibility': get(this.visible)
73
+ };
74
+ }
75
+ setGeoJSONProperties(properties) {
76
+ if (properties == null)
77
+ return;
78
+ if (properties['stroke-color'])
79
+ this.color.set(properties['stroke-color']);
80
+ if (properties['stroke-style']) {
81
+ const dash = dashArrays.entries().find(([, { name }]) => name === properties['stroke-style']);
82
+ if (dash)
83
+ this.dashed.set(dash[0]);
84
+ }
85
+ if (properties['stroke-width'])
86
+ this.width.set(properties['stroke-width']);
87
+ if (properties['stroke-visibility'])
88
+ this.visible.set(properties['stroke-visibility']);
89
+ }
90
+ }
@@ -0,0 +1,19 @@
1
+ import type { LayerSymbol } from './types.js';
2
+ import { MapLayer } from './abstract.js';
3
+ import type { GeometryManager } from '../geometry_manager.js';
4
+ import type { StateObject } from '../state/types.js';
5
+ export declare class MapLayerSymbol extends MapLayer<LayerSymbol> {
6
+ color: import("svelte/store").Writable<string>;
7
+ halo: import("svelte/store").Writable<number>;
8
+ rotate: import("svelte/store").Writable<number>;
9
+ size: import("svelte/store").Writable<number>;
10
+ symbolIndex: import("svelte/store").Writable<number>;
11
+ label: import("svelte/store").Writable<string>;
12
+ haloWidth: import("svelte/store").Readable<number>;
13
+ symbolInfo: import("svelte/store").Readable<import("../symbols.js").SymbolInfo>;
14
+ constructor(manager: GeometryManager, id: string, source: string);
15
+ getState(): StateObject | undefined;
16
+ setState(state: StateObject): void;
17
+ getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
18
+ setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
19
+ }