@versatiles/svelte 1.1.2 → 2.0.1

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 (41) hide show
  1. package/dist/components/BasicMap/BasicMap.svelte +4 -4
  2. package/dist/components/BasicMap/BasicMap.svelte.d.ts +2 -2
  3. package/dist/components/MapEditor/MapEditor.svelte +16 -3
  4. package/dist/components/MapEditor/components/Editor.svelte +56 -40
  5. package/dist/components/MapEditor/components/Editor.svelte.d.ts +1 -1
  6. package/dist/components/MapEditor/components/EditorFill.svelte +42 -12
  7. package/dist/components/MapEditor/components/EditorStroke.svelte +43 -13
  8. package/dist/components/MapEditor/components/EditorSymbol.svelte +105 -34
  9. package/dist/components/MapEditor/components/InputRow.svelte +34 -0
  10. package/dist/components/MapEditor/components/InputRow.svelte.d.ts +9 -0
  11. package/dist/components/MapEditor/components/Sidebar.svelte +119 -109
  12. package/dist/components/MapEditor/components/SidebarPanel.svelte +101 -0
  13. package/dist/components/MapEditor/components/SidebarPanel.svelte.d.ts +10 -0
  14. package/dist/components/MapEditor/components/SymbolSelector.svelte +7 -15
  15. package/dist/components/MapEditor/lib/element/abstract.d.ts +4 -4
  16. package/dist/components/MapEditor/lib/element/abstract.js +2 -2
  17. package/dist/components/MapEditor/lib/element/line.d.ts +3 -4
  18. package/dist/components/MapEditor/lib/element/line.js +0 -1
  19. package/dist/components/MapEditor/lib/element/marker.d.ts +4 -4
  20. package/dist/components/MapEditor/lib/element/polygon.d.ts +3 -3
  21. package/dist/components/MapEditor/lib/geometry_manager.d.ts +20 -10
  22. package/dist/components/MapEditor/lib/geometry_manager.js +42 -52
  23. package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +2 -2
  24. package/dist/components/MapEditor/lib/map_layer/fill.d.ts +4 -3
  25. package/dist/components/MapEditor/lib/map_layer/fill.js +9 -17
  26. package/dist/components/MapEditor/lib/map_layer/line.d.ts +4 -3
  27. package/dist/components/MapEditor/lib/map_layer/line.js +15 -26
  28. package/dist/components/MapEditor/lib/map_layer/symbol.d.ts +5 -4
  29. package/dist/components/MapEditor/lib/map_layer/symbol.js +28 -46
  30. package/dist/components/MapEditor/lib/state/constants.d.ts +4 -0
  31. package/dist/components/MapEditor/lib/state/constants.js +22 -0
  32. package/dist/components/MapEditor/lib/state/manager.d.ts +17 -0
  33. package/dist/components/MapEditor/lib/state/manager.js +87 -0
  34. package/dist/components/MapEditor/lib/state/reader.d.ts +21 -14
  35. package/dist/components/MapEditor/lib/state/reader.js +259 -142
  36. package/dist/components/MapEditor/lib/state/types.d.ts +27 -12
  37. package/dist/components/MapEditor/lib/state/writer.d.ts +18 -14
  38. package/dist/components/MapEditor/lib/state/writer.js +182 -169
  39. package/dist/components/MapEditor/lib/utils.d.ts +2 -5
  40. package/dist/components/MapEditor/lib/utils.js +0 -19
  41. package/package.json +19 -19
@@ -3,9 +3,8 @@ import { MarkerElement } from './element/marker.js';
3
3
  import { LineElement } from './element/line.js';
4
4
  import { PolygonElement } from './element/polygon.js';
5
5
  import { Cursor } from './cursor.js';
6
- import { StateWriter } from './state/writer.js';
7
- import { StateReader } from './state/reader.js';
8
6
  import { SymbolLibrary } from './symbols.js';
7
+ import { StateManager } from './state/manager.js';
9
8
  export class GeometryManager {
10
9
  elements;
11
10
  map;
@@ -13,6 +12,7 @@ export class GeometryManager {
13
12
  canvas;
14
13
  cursor;
15
14
  symbolLibrary;
15
+ state;
16
16
  selectionNodes;
17
17
  constructor(map) {
18
18
  this.elements = writable([]);
@@ -53,7 +53,6 @@ export class GeometryManager {
53
53
  if (e.originalEvent.shiftKey) {
54
54
  selectedNode.delete();
55
55
  this.drawSelectionNodes();
56
- this.saveState();
57
56
  }
58
57
  else {
59
58
  const onMove = (e) => {
@@ -63,8 +62,8 @@ export class GeometryManager {
63
62
  };
64
63
  map.on('mousemove', onMove);
65
64
  map.once('mouseup', () => {
66
- this.saveState();
67
65
  map.off('mousemove', onMove);
66
+ this.state.log();
68
67
  });
69
68
  }
70
69
  });
@@ -79,10 +78,7 @@ export class GeometryManager {
79
78
  this.selectElement(undefined);
80
79
  e.preventDefault();
81
80
  });
82
- map.on('moveend', () => this.saveState());
83
- const hash = location.hash.slice(1);
84
- if (hash)
85
- this.loadState(hash);
81
+ this.state = new StateManager(this);
86
82
  }
87
83
  selectElement(element) {
88
84
  if (element == get(this.selectedElement))
@@ -107,48 +103,42 @@ export class GeometryManager {
107
103
  const center = this.map.getCenter();
108
104
  return {
109
105
  map: {
110
- point: [center.lng, center.lat],
106
+ center: [center.lng, center.lat],
111
107
  zoom: this.map.getZoom()
112
108
  },
113
109
  elements: get(this.elements).map((element) => element.getState())
114
110
  };
115
111
  }
116
- async saveState() {
117
- const writer = new StateWriter();
118
- writer.writeObject(this.getState());
119
- location.hash = await writer.getBase64compressed();
120
- }
121
- async loadState(hash) {
122
- if (!hash)
112
+ setState(state) {
113
+ if (!state)
123
114
  return;
124
- try {
125
- const reader = await StateReader.fromBase64compressed(hash);
126
- const state = reader.readObject();
127
- if (!state)
128
- return;
129
- if (state.map?.zoom)
115
+ this.selectElement(undefined);
116
+ this.elements.update((elements) => {
117
+ elements.forEach((e) => e.destroy());
118
+ return [];
119
+ });
120
+ if (state.map) {
121
+ if (state.map.zoom)
130
122
  this.map.setZoom(state.map.zoom);
131
- if (state.map?.point) {
132
- this.map.setCenter({ lng: state.map.point[0], lat: state.map.point[1] });
133
- }
134
- if (state.elements) {
135
- const elements = state.elements.map((element) => {
136
- switch (element.type) {
137
- case 'marker':
138
- return MarkerElement.fromState(this, element);
139
- case 'line':
140
- return LineElement.fromState(this, element);
141
- case 'polygon':
142
- return PolygonElement.fromState(this, element);
143
- default:
144
- throw new Error('Unknown element type');
145
- }
146
- });
147
- this.elements.set(elements);
123
+ if (state.map.center) {
124
+ const [lng, lat] = state.map.center;
125
+ this.map.setCenter({ lng, lat });
148
126
  }
149
127
  }
150
- catch (error) {
151
- console.error(error);
128
+ if (state.elements) {
129
+ const elements = state.elements.map((element) => {
130
+ switch (element.type) {
131
+ case 'marker':
132
+ return MarkerElement.fromState(this, element);
133
+ case 'line':
134
+ return LineElement.fromState(this, element);
135
+ case 'polygon':
136
+ return PolygonElement.fromState(this, element);
137
+ default:
138
+ throw new Error('Unknown element type');
139
+ }
140
+ });
141
+ this.elements.set(elements);
152
142
  }
153
143
  }
154
144
  getElement(index) {
@@ -156,28 +146,29 @@ export class GeometryManager {
156
146
  }
157
147
  addNewMarker() {
158
148
  const element = new MarkerElement(this);
159
- this.addElement(element);
149
+ this.appendElement(element);
150
+ this.selectElement(element);
160
151
  return element;
161
152
  }
162
153
  addNewLine() {
163
154
  const element = new LineElement(this);
164
- this.addElement(element);
155
+ this.appendElement(element);
156
+ this.selectElement(element);
165
157
  return element;
166
158
  }
167
159
  addNewPolygon() {
168
160
  const element = new PolygonElement(this);
169
- this.addElement(element);
161
+ this.appendElement(element);
162
+ this.selectElement(element);
170
163
  return element;
171
164
  }
172
- addElement(element) {
165
+ appendElement(element) {
173
166
  this.elements.update((elements) => [...elements, element]);
174
- this.saveState();
175
167
  }
176
- deleteElement(element) {
177
- this.elements.update((elements) => elements.filter((e) => e !== element));
168
+ removeElement(element) {
178
169
  if (get(this.selectedElement) === element)
179
170
  this.selectElement(undefined);
180
- this.saveState();
171
+ this.elements.update((elements) => elements.filter((e) => e !== element));
181
172
  }
182
173
  getGeoJSON() {
183
174
  const center = this.map.getCenter();
@@ -191,7 +182,7 @@ export class GeometryManager {
191
182
  };
192
183
  }
193
184
  addGeoJSON(geojson) {
194
- if ('map' in geojson) {
185
+ if ('map' in geojson && geojson.map) {
195
186
  const { map } = geojson;
196
187
  if (typeof map.zoom === 'number') {
197
188
  this.map.setZoom(map.zoom);
@@ -218,8 +209,7 @@ export class GeometryManager {
218
209
  default:
219
210
  throw new Error(`Unknown geometry type "${feature.geometry.type}"`);
220
211
  }
221
- this.addElement(element);
212
+ this.appendElement(element);
222
213
  }
223
- this.saveState();
224
214
  }
225
215
  }
@@ -1,6 +1,6 @@
1
1
  import type { LayerFill, LayerLine, LayerSymbol } from './types.js';
2
2
  import type { GeometryManager } from '../geometry_manager.js';
3
- import type { StateObject } from '../state/types.js';
3
+ import type { StateStyle } from '../state/types.js';
4
4
  type LayerSpec = LayerFill | LayerLine | LayerSymbol;
5
5
  type Events = 'click' | 'mousedown' | 'mousemove' | 'mouseup';
6
6
  type MouseEventHandler = (event: maplibregl.MapMouseEvent) => void;
@@ -23,7 +23,7 @@ export declare abstract class MapLayer<T extends LayerSpec> {
23
23
  updateLayout(obj: T['layout']): void;
24
24
  updateLayout<K extends keyof T['layout'], V extends T['layout'][K]>(key: K, value: V): void;
25
25
  destroy(): void;
26
- abstract getState(): StateObject | undefined;
26
+ abstract getState(): StateStyle | undefined;
27
27
  abstract getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
28
28
  abstract setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
29
29
  }
@@ -1,7 +1,7 @@
1
1
  import type { LayerFill } from './types.js';
2
2
  import { MapLayer } from './abstract.js';
3
3
  import type { GeometryManager } from '../geometry_manager.js';
4
- import type { StateObject } from '../state/types.js';
4
+ import type { StateStyle } from '../state/types.js';
5
5
  interface Fill {
6
6
  xf: number;
7
7
  yf: number;
@@ -15,9 +15,10 @@ export declare class MapLayerFill extends MapLayer<LayerFill> {
15
15
  color: import("svelte/store").Writable<string>;
16
16
  opacity: import("svelte/store").Writable<number>;
17
17
  pattern: import("svelte/store").Writable<number>;
18
+ static readonly defaultStyle: StateStyle;
18
19
  constructor(manager: GeometryManager, id: string, source: string);
19
- getState(): StateObject | undefined;
20
- setState(state: StateObject): void;
20
+ getState(): StateStyle | undefined;
21
+ setState(state: StateStyle): void;
21
22
  getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
22
23
  setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
23
24
  }
@@ -12,6 +12,11 @@ export class MapLayerFill extends MapLayer {
12
12
  color = writable('#ff0000');
13
13
  opacity = writable(1);
14
14
  pattern = writable(0);
15
+ static defaultStyle = {
16
+ color: '#ff0000',
17
+ opacity: 1,
18
+ pattern: 0
19
+ };
15
20
  constructor(manager, id, source) {
16
21
  super(manager, id);
17
22
  this.addLayer(source, 'fill', {}, {
@@ -47,29 +52,16 @@ export class MapLayerFill extends MapLayer {
47
52
  this.map.addImage(name, { width: size, height: size, data });
48
53
  this.updatePaint('fill-pattern', name);
49
54
  };
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
- });
55
+ this.color.subscribe(() => updatePattern());
56
+ this.pattern.subscribe(() => updatePattern());
57
+ this.opacity.subscribe((value) => this.updatePaint('fill-opacity', value));
62
58
  }
63
59
  getState() {
64
60
  return removeDefaultFields({
65
61
  color: get(this.color),
66
62
  opacity: get(this.opacity),
67
63
  pattern: get(this.pattern)
68
- }, {
69
- color: '#ff0000',
70
- opacity: 1,
71
- pattern: 0
72
- });
64
+ }, MapLayerFill.defaultStyle);
73
65
  }
74
66
  setState(state) {
75
67
  if (state.color)
@@ -1,20 +1,21 @@
1
1
  import type { LayerLine } from './types.js';
2
2
  import { MapLayer } from './abstract.js';
3
3
  import type { GeometryManager } from '../geometry_manager.js';
4
- import type { StateObject } from '../state/types.js';
4
+ import type { StateStyle } from '../state/types.js';
5
5
  export declare const dashArrays: Map<number, {
6
6
  name: string;
7
7
  array: number[] | undefined;
8
8
  }>;
9
9
  export declare class MapLayerLine extends MapLayer<LayerLine> {
10
+ static readonly defaultStyle: StateStyle;
10
11
  color: import("svelte/store").Writable<string>;
11
12
  dashed: import("svelte/store").Writable<number>;
12
13
  visible: import("svelte/store").Writable<boolean>;
13
14
  width: import("svelte/store").Writable<number>;
14
15
  dashArray: import("svelte/store").Readable<number[]>;
15
16
  constructor(manager: GeometryManager, id: string, source: string);
16
- getState(): StateObject | undefined;
17
- setState(state: StateObject): void;
17
+ getState(): StateStyle | undefined;
18
+ setState(state: StateStyle): void;
18
19
  getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
19
20
  setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
20
21
  }
@@ -8,10 +8,16 @@ export const dashArrays = new Map([
8
8
  [2, { name: 'dotted', array: [0, 2] }]
9
9
  ]);
10
10
  export class MapLayerLine extends MapLayer {
11
- color = writable('#ff0000');
12
- dashed = writable(0);
13
- visible = writable(true);
14
- width = writable(2);
11
+ static defaultStyle = {
12
+ color: '#ff0000',
13
+ pattern: 0,
14
+ visible: true,
15
+ width: 2
16
+ };
17
+ color = writable(MapLayerLine.defaultStyle.color);
18
+ dashed = writable(MapLayerLine.defaultStyle.pattern);
19
+ visible = writable(MapLayerLine.defaultStyle.visible);
20
+ width = writable(MapLayerLine.defaultStyle.width);
15
21
  dashArray = derived(this.dashed, (dashed) => dashArrays.get(dashed)?.array ?? [100]);
16
22
  constructor(manager, id, source) {
17
23
  super(manager, id);
@@ -24,22 +30,10 @@ export class MapLayerLine extends MapLayer {
24
30
  'line-dasharray': get(this.dashArray),
25
31
  'line-width': get(this.width)
26
32
  });
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
- });
33
+ this.color.subscribe((v) => this.updatePaint('line-color', Color.parse(v)));
34
+ this.dashArray.subscribe((v) => this.updatePaint('line-dasharray', v));
35
+ this.visible.subscribe((v) => this.updateLayout('visibility', v ? 'visible' : 'none'));
36
+ this.width.subscribe((v) => this.updatePaint('line-width', v));
43
37
  }
44
38
  getState() {
45
39
  return removeDefaultFields({
@@ -47,12 +41,7 @@ export class MapLayerLine extends MapLayer {
47
41
  pattern: get(this.dashed),
48
42
  visible: get(this.visible),
49
43
  width: get(this.width)
50
- }, {
51
- color: '#ff0000',
52
- pattern: 0,
53
- visible: true,
54
- width: 2
55
- });
44
+ }, MapLayerLine.defaultStyle);
56
45
  }
57
46
  setState(state) {
58
47
  if (state.color)
@@ -2,7 +2,7 @@ import { type Writable } from 'svelte/store';
2
2
  import type { LayerSymbol } from './types.js';
3
3
  import { MapLayer } from './abstract.js';
4
4
  import type { GeometryManager } from '../geometry_manager.js';
5
- import type { StateObject } from '../state/types.js';
5
+ import type { StateStyle } from '../state/types.js';
6
6
  interface LabelAlign {
7
7
  index: 0 | 1 | 2 | 3 | 4;
8
8
  name: string;
@@ -10,19 +10,20 @@ interface LabelAlign {
10
10
  }
11
11
  export declare const labelPositions: LabelAlign[];
12
12
  export declare class MapLayerSymbol extends MapLayer<LayerSymbol> {
13
+ static readonly defaultStyle: StateStyle;
13
14
  color: Writable<string>;
14
15
  halo: Writable<number>;
15
16
  rotate: Writable<number>;
16
17
  size: Writable<number>;
17
18
  symbolIndex: Writable<number>;
18
19
  label: Writable<string>;
19
- labelAlign: Writable<0 | 2 | 1 | 4 | 3>;
20
+ labelAlign: Writable<number>;
20
21
  symbolInfo: import("svelte/store").Readable<import("../symbols.js").SymbolInfo>;
21
22
  textAnchor: import("svelte/store").Readable<"center" | "top" | "bottom" | "right" | "left" | undefined>;
22
23
  textVariableAnchor: import("svelte/store").Readable<("center" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "top" | "bottom" | "right" | "left")[] | undefined>;
23
24
  constructor(manager: GeometryManager, id: string, source: string);
24
- getState(): StateObject | undefined;
25
- setState(state: StateObject): void;
25
+ getState(): StateStyle | undefined;
26
+ setState(state: StateStyle): void;
26
27
  getGeoJSONProperties(): GeoJSON.GeoJsonProperties;
27
28
  setGeoJSONProperties(properties: GeoJSON.GeoJsonProperties): void;
28
29
  }
@@ -10,23 +10,23 @@ export const labelPositions = [
10
10
  { index: 3, name: 'top', anchor: 'bottom' },
11
11
  { index: 4, name: 'bottom', anchor: 'top' }
12
12
  ];
13
- const defaultStyle = {
14
- color: '#ff0000',
15
- rotate: 0,
16
- size: 1,
17
- halo: 1,
18
- pattern: 38,
19
- label: '',
20
- align: 0
21
- };
22
13
  export class MapLayerSymbol extends MapLayer {
23
- color = writable(defaultStyle.color);
24
- halo = writable(defaultStyle.halo);
25
- rotate = writable(defaultStyle.rotate);
26
- size = writable(defaultStyle.size);
27
- symbolIndex = writable(defaultStyle.pattern);
28
- label = writable(defaultStyle.label);
29
- labelAlign = writable(defaultStyle.align);
14
+ static defaultStyle = {
15
+ color: '#ff0000',
16
+ rotate: 0,
17
+ size: 1,
18
+ halo: 1,
19
+ pattern: 38,
20
+ label: '',
21
+ align: 0
22
+ };
23
+ color = writable(MapLayerSymbol.defaultStyle.color);
24
+ halo = writable(MapLayerSymbol.defaultStyle.halo);
25
+ rotate = writable(MapLayerSymbol.defaultStyle.rotate);
26
+ size = writable(MapLayerSymbol.defaultStyle.size);
27
+ symbolIndex = writable(MapLayerSymbol.defaultStyle.pattern);
28
+ label = writable(MapLayerSymbol.defaultStyle.label);
29
+ labelAlign = writable(MapLayerSymbol.defaultStyle.align);
30
30
  symbolInfo = derived(this.symbolIndex, (index) => getSymbol(index));
31
31
  textAnchor = derived(this.labelAlign, (index) => {
32
32
  return lookupLabelAlign(index).anchor;
@@ -45,9 +45,9 @@ export class MapLayerSymbol extends MapLayer {
45
45
  'icon-image': get(this.symbolInfo).image,
46
46
  'icon-offset': get(this.symbolInfo).offset,
47
47
  'icon-allow-overlap': true,
48
- 'icon-rotate': defaultStyle.rotate,
49
- 'icon-size': defaultStyle.size,
50
- 'text-field': defaultStyle.label,
48
+ 'icon-rotate': get(this.rotate),
49
+ 'icon-size': get(this.size),
50
+ 'text-field': get(this.label),
51
51
  'text-font': ['noto_sans_regular'],
52
52
  'text-justify': 'left',
53
53
  'text-overlap': 'always',
@@ -55,44 +55,27 @@ export class MapLayerSymbol extends MapLayer {
55
55
  'text-variable-anchor': get(this.textVariableAnchor),
56
56
  'text-anchor': get(this.textAnchor)
57
57
  }, {
58
- 'icon-color': defaultStyle.color,
58
+ 'icon-color': get(this.color),
59
59
  'icon-halo-blur': 0,
60
60
  'icon-halo-color': '#FFFFFF',
61
- 'icon-halo-width': defaultStyle.halo,
61
+ 'icon-halo-width': get(this.halo),
62
62
  'icon-opacity': 1,
63
63
  'text-halo-blur': 0,
64
64
  'text-halo-color': '#FFFFFF',
65
- 'text-halo-width': defaultStyle.halo
66
- });
67
- this.color.subscribe((v) => {
68
- this.updatePaint('icon-color', Color.parse(v));
69
- this.manager.saveState();
65
+ 'text-halo-width': get(this.halo)
70
66
  });
67
+ this.color.subscribe((v) => this.updatePaint('icon-color', Color.parse(v)));
71
68
  this.halo.subscribe((v) => {
72
69
  this.updatePaint('icon-halo-width', v);
73
70
  this.updatePaint('text-halo-width', v);
74
- this.manager.saveState();
75
- });
76
- this.label.subscribe((v) => {
77
- this.updateLayout('text-field', v);
78
- this.manager.saveState();
79
- });
80
- this.textAnchor.subscribe((v) => {
81
- this.updateLayout('text-anchor', v);
82
- this.manager.saveState();
83
- });
84
- this.textVariableAnchor.subscribe((v) => {
85
- this.updateLayout('text-variable-anchor', v);
86
- this.manager.saveState();
87
- });
88
- this.rotate.subscribe((v) => {
89
- this.updateLayout('icon-rotate', v);
90
- this.manager.saveState();
91
71
  });
72
+ this.label.subscribe((v) => this.updateLayout('text-field', v));
73
+ this.textAnchor.subscribe((v) => this.updateLayout('text-anchor', v));
74
+ this.textVariableAnchor.subscribe((v) => this.updateLayout('text-variable-anchor', v));
75
+ this.rotate.subscribe((v) => this.updateLayout('icon-rotate', v));
92
76
  this.size.subscribe((v) => {
93
77
  this.updateLayout('icon-size', v);
94
78
  this.updateLayout('text-size', v * 16);
95
- this.manager.saveState();
96
79
  });
97
80
  this.symbolInfo.subscribe((v) => {
98
81
  if (v.image == null) {
@@ -102,7 +85,6 @@ export class MapLayerSymbol extends MapLayer {
102
85
  this.updateLayout('icon-image', v.image);
103
86
  this.updateLayout('icon-offset', v.offset);
104
87
  }
105
- this.manager.saveState();
106
88
  });
107
89
  }
108
90
  getState() {
@@ -114,7 +96,7 @@ export class MapLayerSymbol extends MapLayer {
114
96
  pattern: get(this.symbolIndex),
115
97
  label: get(this.label),
116
98
  align: get(this.labelAlign)
117
- }, defaultStyle);
99
+ }, MapLayerSymbol.defaultStyle);
118
100
  }
119
101
  setState(state) {
120
102
  if (state.color)
@@ -0,0 +1,4 @@
1
+ export declare const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
2
+ export declare const BASE64_CODE2BITS: [boolean, boolean, boolean, boolean, boolean, boolean][];
3
+ export declare const CHAR_VALUE2CODE: number[];
4
+ export declare const CHAR_CODE2VALUE: number[];
@@ -0,0 +1,22 @@
1
+ export const BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
2
+ export const BASE64_CODE2BITS = [];
3
+ for (let i = 0; i < BASE64_CHARS.length; i++) {
4
+ BASE64_CODE2BITS[BASE64_CHARS.charCodeAt(i)] = [
5
+ (i & 32) > 0,
6
+ (i & 16) > 0,
7
+ (i & 8) > 0,
8
+ (i & 4) > 0,
9
+ (i & 2) > 0,
10
+ (i & 1) > 0
11
+ ];
12
+ }
13
+ export const CHAR_VALUE2CODE = [
14
+ 32, 101, 116, 97, 110, 105, 111, 115, 114, 108, 100, 104, 99, 117, 109, 112, 102, 103, 46, 121,
15
+ 98, 119, 44, 118, 48, 107, 49, 83, 84, 67, 50, 56, 53, 65, 57, 120, 51, 73, 45, 54, 52, 55, 77,
16
+ 66, 34, 39, 80, 69, 78, 70, 82, 68, 85, 113, 76, 71, 74, 72, 79, 87, 106, 122, 47, 60, 62, 75, 41,
17
+ 40, 86, 89, 58, 81, 90, 88, 59, 63, 94, 38, 43, 91, 93, 36, 33, 42, 61, 126, 95, 123, 64, 0, 1, 2,
18
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
19
+ 29, 30, 31, 35, 37, 92, 96, 124, 125, 127
20
+ ];
21
+ export const CHAR_CODE2VALUE = [];
22
+ CHAR_VALUE2CODE.forEach((c, v) => (CHAR_CODE2VALUE[c] = v));
@@ -0,0 +1,17 @@
1
+ import type { GeometryManager } from '../geometry_manager.js';
2
+ export declare class StateManager {
3
+ geometryManager: GeometryManager;
4
+ private disableLogging;
5
+ constructor(geometryManager: GeometryManager);
6
+ getHash(): string;
7
+ setHash(hash: string): void;
8
+ private history;
9
+ private historyIndex;
10
+ undoEnabled: import("svelte/store").Writable<boolean>;
11
+ redoEnabled: import("svelte/store").Writable<boolean>;
12
+ private resetHistory;
13
+ log(): void;
14
+ undo(): void;
15
+ redo(): void;
16
+ private updateButtons;
17
+ }
@@ -0,0 +1,87 @@
1
+ import { writable } from 'svelte/store';
2
+ import { StateReader } from './reader.js';
3
+ import { StateWriter } from './writer.js';
4
+ const MAXLENGTH = 100;
5
+ export class StateManager {
6
+ geometryManager;
7
+ disableLogging = false;
8
+ constructor(geometryManager) {
9
+ this.geometryManager = geometryManager;
10
+ this.resetHistory();
11
+ }
12
+ getHash() {
13
+ const writer = new StateWriter();
14
+ writer.writeRoot(this.geometryManager.getState());
15
+ return writer.asBase64();
16
+ }
17
+ setHash(hash) {
18
+ if (!hash)
19
+ return;
20
+ try {
21
+ const state = StateReader.fromBase64(hash).readRoot();
22
+ this.disableLogging = true;
23
+ this.geometryManager.setState(state);
24
+ this.disableLogging = false;
25
+ this.history = [{ ...state, map: undefined }];
26
+ this.historyIndex = 0;
27
+ this.updateButtons();
28
+ }
29
+ catch (error) {
30
+ console.error(error);
31
+ }
32
+ }
33
+ // History of state hashes
34
+ // The first element is the most recent state
35
+ history = [];
36
+ // The index of the current state in the history
37
+ // 0 means the most recent state
38
+ // 1 means the second most recent state
39
+ historyIndex = 0;
40
+ undoEnabled = writable(false);
41
+ redoEnabled = writable(false);
42
+ resetHistory() {
43
+ this.history = [this.geometryManager.getState()];
44
+ this.historyIndex = 0;
45
+ this.updateButtons();
46
+ }
47
+ log() {
48
+ if (this.disableLogging)
49
+ return;
50
+ const state = this.geometryManager.getState();
51
+ state.map = undefined; // Remove map state from history
52
+ if (this.historyIndex > 0) {
53
+ this.history.splice(0, this.historyIndex);
54
+ this.historyIndex = 0;
55
+ }
56
+ this.history.unshift(state);
57
+ // Remove old history
58
+ if (this.history.length > MAXLENGTH) {
59
+ this.history.length = MAXLENGTH;
60
+ }
61
+ this.updateButtons();
62
+ }
63
+ undo() {
64
+ if (this.historyIndex < this.history.length - 1) {
65
+ this.historyIndex++;
66
+ const state = this.history[this.historyIndex];
67
+ this.disableLogging = true;
68
+ this.geometryManager.setState(state);
69
+ this.disableLogging = false;
70
+ this.updateButtons();
71
+ }
72
+ }
73
+ redo() {
74
+ if (this.historyIndex > 0) {
75
+ this.historyIndex--;
76
+ const state = this.history[this.historyIndex];
77
+ this.disableLogging = true;
78
+ this.geometryManager.setState(state);
79
+ this.disableLogging = false;
80
+ this.updateButtons();
81
+ }
82
+ }
83
+ updateButtons() {
84
+ this.undoEnabled.set(this.historyIndex < this.history.length - 1);
85
+ this.redoEnabled.set(this.historyIndex > 0);
86
+ }
87
+ }