@geogirafe/lib-geoportal 1.2.0-dev.2836809138 → 1.2.0-dev.2844989778
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/api/apigeogirafeapp.js +4 -2
- package/api/style.css +4 -10
- package/assets/i18n/de.json +7 -3
- package/assets/i18n/en.json +4 -0
- package/assets/i18n/fr.json +4 -0
- package/assets/i18n/it.json +4 -0
- package/components/layout/component.d.ts +34 -3
- package/components/layout/component.js +66 -28
- package/components/layout/style.css +13 -0
- package/components/main.d.ts +1 -0
- package/components/main.js +1 -0
- package/components/map-2d/component.d.ts +0 -6
- package/components/map-2d/component.js +3 -22
- package/components/map-3d/component.d.ts +4 -2
- package/components/map-3d/component.js +7 -18
- package/components/map-grid/component.d.ts +70 -0
- package/components/map-grid/component.js +206 -0
- package/components/map-grid/style.css +99 -0
- package/components/menu-buttons-mobile/MenuMobile3dButton.js +3 -1
- package/package.json +1 -1
- package/styles/iframe.css +4 -10
- package/styles/index.css +4 -10
- package/styles/mobile.css +4 -10
- package/templates/iframe.html +2 -2
- package/templates/index.html +2 -2
- package/templates/mobile.html +2 -2
- package/templates/public/about.json +1 -1
- package/tools/app/geogirafeapp-mobile.js +2 -0
- package/tools/app/geogirafeapp.js +2 -0
- package/tools/configuration/girafeconfig.d.ts +4 -0
- package/tools/configuration/girafeconfig.js +20 -2
- package/tools/main.d.ts +3 -0
- package/tools/main.js +2 -0
- package/tools/share/serializers/globeserializer.d.ts +2 -0
- package/tools/share/serializers/globeserializer.js +26 -4
- package/tools/share/serializers/layoutserializer.d.ts +17 -0
- package/tools/share/serializers/layoutserializer.js +44 -0
- package/tools/share/stateserializer.js +3 -0
- package/tools/state/globe.d.ts +0 -1
- package/tools/state/globe.js +0 -1
- package/tools/state/layout.d.ts +62 -0
- package/tools/state/layout.js +67 -0
- package/tools/state/state.d.ts +2 -0
- package/tools/state/state.js +8 -0
- package/tools/state/statemanager.d.ts +1 -0
- package/tools/state/statemanager.js +8 -0
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import LayoutSerializer from './layoutserializer.js';
|
|
2
|
+
/**
|
|
3
|
+
* The layouts the display modes of the previous versions correspond to.
|
|
4
|
+
*
|
|
5
|
+
* <code>globe.display</code> was replaced by <code>state.layout</code>, but the states that were
|
|
6
|
+
* shared before that change still contain it and have to keep working. Such a state never contains
|
|
7
|
+
* a layout, so there is no risk of overwriting a layout that was deserialized before.
|
|
8
|
+
*/
|
|
9
|
+
const LEGACY_DISPLAYS = {
|
|
10
|
+
'2D': { type: '1x1', cells: ['map-2d'], sizes: { columns: [100], rows: [100] } },
|
|
11
|
+
'3D': { type: '1x1', cells: ['map-3d'], sizes: { columns: [100], rows: [100] } },
|
|
12
|
+
'2D/3D': { type: '2x1', cells: ['map-2d', 'map-3d'], sizes: { columns: [45, 55], rows: [100] } }
|
|
13
|
+
};
|
|
1
14
|
export default class GlobeSerializer {
|
|
2
15
|
context;
|
|
3
16
|
constructor(context) {
|
|
@@ -8,7 +21,6 @@ export default class GlobeSerializer {
|
|
|
8
21
|
}
|
|
9
22
|
brainSerialize(globe) {
|
|
10
23
|
return JSON.stringify({
|
|
11
|
-
display: globe.display,
|
|
12
24
|
shadows: globe.shadows,
|
|
13
25
|
shadowsTimestamp: globe.shadowsTimestamp,
|
|
14
26
|
camera: globe.camera
|
|
@@ -17,9 +29,6 @@ export default class GlobeSerializer {
|
|
|
17
29
|
brainDeserialize(str) {
|
|
18
30
|
const parsedGlobe = JSON.parse(str);
|
|
19
31
|
const globe = this.globe;
|
|
20
|
-
if (parsedGlobe.display) {
|
|
21
|
-
globe.display = parsedGlobe.display;
|
|
22
|
-
}
|
|
23
32
|
if (parsedGlobe.shadows !== undefined) {
|
|
24
33
|
globe.shadows = parsedGlobe.shadows;
|
|
25
34
|
}
|
|
@@ -28,5 +37,18 @@ export default class GlobeSerializer {
|
|
|
28
37
|
}
|
|
29
38
|
globe.camera = parsedGlobe.camera ?? null;
|
|
30
39
|
globe.loaded = false;
|
|
40
|
+
this.deserializeLegacyDisplay(parsedGlobe.display);
|
|
41
|
+
}
|
|
42
|
+
/** Applies the layout a display mode of the previous versions corresponds to. */
|
|
43
|
+
deserializeLegacyDisplay(display) {
|
|
44
|
+
if (display === undefined) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const legacyLayout = LEGACY_DISPLAYS[display];
|
|
48
|
+
if (!legacyLayout) {
|
|
49
|
+
console.warn(`${display} is not a known display mode. The shared display mode will be ignored.`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
new LayoutSerializer(this.context).applyLayout(legacyLayout.type, legacyLayout.cells, legacyLayout.sizes);
|
|
31
53
|
}
|
|
32
54
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import IGirafeContext from '../../context/icontext.js';
|
|
2
|
+
import { IBrainSerializer } from '../../state/brain/serialize.js';
|
|
3
|
+
import LayoutState, { CellContent, LayoutType } from '../../state/layout.js';
|
|
4
|
+
export default class LayoutSerializer implements IBrainSerializer<LayoutState> {
|
|
5
|
+
private readonly context;
|
|
6
|
+
constructor(context: IGirafeContext);
|
|
7
|
+
private get layout();
|
|
8
|
+
brainSerialize(layout: LayoutState): string;
|
|
9
|
+
brainDeserialize(str: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Applies a layout to the state, ignoring the values that are not valid anymore.
|
|
12
|
+
* A shared state can have been created by another version of the application,
|
|
13
|
+
* in which other components or other layouts were available.
|
|
14
|
+
*/
|
|
15
|
+
applyLayout(type: LayoutType, cells?: CellContent[], sizes?: LayoutState['sizes']): void;
|
|
16
|
+
private getValidSizes;
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { distributeCells, getDefaultSizes, getGridSize, isCellComponent, isLayoutType } from '../../state/layout.js';
|
|
2
|
+
export default class LayoutSerializer {
|
|
3
|
+
context;
|
|
4
|
+
constructor(context) {
|
|
5
|
+
this.context = context;
|
|
6
|
+
}
|
|
7
|
+
get layout() {
|
|
8
|
+
return this.context.stateManager.state.layout;
|
|
9
|
+
}
|
|
10
|
+
brainSerialize(layout) {
|
|
11
|
+
return JSON.stringify({
|
|
12
|
+
type: layout.type,
|
|
13
|
+
cells: layout.cells,
|
|
14
|
+
sizes: layout.sizes
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
brainDeserialize(str) {
|
|
18
|
+
const parsedLayout = JSON.parse(str);
|
|
19
|
+
if (!isLayoutType(parsedLayout.type)) {
|
|
20
|
+
console.warn(`${parsedLayout.type} is not a valid layout. The shared layout will be ignored.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.applyLayout(parsedLayout.type, parsedLayout.cells, parsedLayout.sizes);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Applies a layout to the state, ignoring the values that are not valid anymore.
|
|
27
|
+
* A shared state can have been created by another version of the application,
|
|
28
|
+
* in which other components or other layouts were available.
|
|
29
|
+
*/
|
|
30
|
+
applyLayout(type, cells, sizes) {
|
|
31
|
+
const layout = this.layout;
|
|
32
|
+
layout.type = type;
|
|
33
|
+
layout.cells = distributeCells(type, (cells ?? []).map((cell) => (isCellComponent(cell) ? cell : null)));
|
|
34
|
+
layout.sizes = this.getValidSizes(type, sizes);
|
|
35
|
+
}
|
|
36
|
+
getValidSizes(type, sizes) {
|
|
37
|
+
const defaultSizes = getDefaultSizes(type);
|
|
38
|
+
const { columns, rows } = getGridSize(type);
|
|
39
|
+
if (sizes?.columns?.length !== columns || sizes?.rows?.length !== rows) {
|
|
40
|
+
return defaultSizes;
|
|
41
|
+
}
|
|
42
|
+
return { columns: sizes.columns, rows: sizes.rows };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -13,6 +13,8 @@ import ObjectSelection from '../state/objectselection.js';
|
|
|
13
13
|
import GraphicalInterface from '../state/graphicalInterface.js';
|
|
14
14
|
import InterfaceSerializer from './serializers/interfaceserializer.js';
|
|
15
15
|
import GlobeSerializer from './serializers/globeserializer.js';
|
|
16
|
+
import LayoutState from '../state/layout.js';
|
|
17
|
+
import LayoutSerializer from './serializers/layoutserializer.js';
|
|
16
18
|
class StateSerializer extends GirafeSingleton {
|
|
17
19
|
brainSerializer = new BrainSerializer();
|
|
18
20
|
initializeSingleton() {
|
|
@@ -22,6 +24,7 @@ class StateSerializer extends GirafeSingleton {
|
|
|
22
24
|
this.addSerializer(ObjectSelection, new SelectionSerializer(this.context));
|
|
23
25
|
this.addSerializer(GraphicalInterface, new InterfaceSerializer(this.context));
|
|
24
26
|
this.addSerializer(GlobeState, new GlobeSerializer(this.context));
|
|
27
|
+
this.addSerializer(LayoutState, new LayoutSerializer(this.context));
|
|
25
28
|
}
|
|
26
29
|
addSerializer(type, serializerData) {
|
|
27
30
|
this.brainSerializer.addSerializer(type, serializerData);
|
package/tools/state/globe.d.ts
CHANGED
package/tools/state/globe.js
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The available Layouts of the Map Grid.
|
|
3
|
+
* The name of a Layout is <number of columns>x<number of rows>.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LAYOUT_TYPES: readonly ["1x1", "2x1", "1x2", "2x2"];
|
|
6
|
+
export type LayoutType = (typeof LAYOUT_TYPES)[number];
|
|
7
|
+
/** Minimal size of a Column or of a Row of the Grid, in percent of the Grid. */
|
|
8
|
+
export declare const MIN_CELL_SIZE = 15;
|
|
9
|
+
/** Maximal size of a Column or of a Row of the Grid, in percent of the Grid. */
|
|
10
|
+
export declare const MAX_CELL_SIZE = 85;
|
|
11
|
+
/**
|
|
12
|
+
* The Components that can be displayed in a Cell of the Grid.
|
|
13
|
+
* To make a new Component available to the user, it is enough to add it to this list
|
|
14
|
+
* (and to add its Element to the Grid in the HTML of the application).
|
|
15
|
+
*/
|
|
16
|
+
export declare const AVAILABLE_CELL_COMPONENTS: readonly [{
|
|
17
|
+
readonly id: "map-2d";
|
|
18
|
+
readonly tagName: "girafe-map-2d";
|
|
19
|
+
readonly label: "2D Map";
|
|
20
|
+
}, {
|
|
21
|
+
readonly id: "map-3d";
|
|
22
|
+
readonly tagName: "girafe-map-3d";
|
|
23
|
+
readonly label: "3D Map";
|
|
24
|
+
}];
|
|
25
|
+
export type CellComponent = (typeof AVAILABLE_CELL_COMPONENTS)[number]['id'];
|
|
26
|
+
/** The content of a Cell of the Grid: a Component, or null when the Cell is empty. */
|
|
27
|
+
export type CellContent = CellComponent | null;
|
|
28
|
+
export declare function isLayoutType(value: unknown): value is LayoutType;
|
|
29
|
+
export declare function isCellComponent(value: unknown): value is CellComponent;
|
|
30
|
+
/** The number of columns and of rows of a Layout. */
|
|
31
|
+
export declare function getGridSize(type: LayoutType): {
|
|
32
|
+
columns: number;
|
|
33
|
+
rows: number;
|
|
34
|
+
};
|
|
35
|
+
/** The sizes, in percent, of the equally distributed columns and rows of a Layout. */
|
|
36
|
+
export declare function getDefaultSizes(type: LayoutType): {
|
|
37
|
+
columns: number[];
|
|
38
|
+
rows: number[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Distributes the Components on the Cells of a Layout.
|
|
42
|
+
* The Components that are already placed keep their Cell as long as it still exists,
|
|
43
|
+
* and the Cells that are added by the new Layout are filled with the Components
|
|
44
|
+
* that are not placed anywhere yet.
|
|
45
|
+
*/
|
|
46
|
+
export declare function distributeCells(type: LayoutType, currentCells: CellContent[]): CellContent[];
|
|
47
|
+
/**
|
|
48
|
+
* The Layout of the Map Grid: which Layout is displayed, which Component is displayed
|
|
49
|
+
* in each of its Cells, and the sizes of its columns and rows (in percent),
|
|
50
|
+
* which the user can change by dragging the splitters.
|
|
51
|
+
*
|
|
52
|
+
* The Cells are indexed row by row: in a 2x2 Layout, the Cell 0 is the top-left one,
|
|
53
|
+
* the Cell 1 the top-right one, the Cell 2 the bottom-left one and the Cell 3 the bottom-right one.
|
|
54
|
+
*/
|
|
55
|
+
export default class LayoutState {
|
|
56
|
+
type: LayoutType;
|
|
57
|
+
cells: CellContent[];
|
|
58
|
+
sizes: {
|
|
59
|
+
columns: number[];
|
|
60
|
+
rows: number[];
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* The available Layouts of the Map Grid.
|
|
4
|
+
* The name of a Layout is <number of columns>x<number of rows>.
|
|
5
|
+
*/
|
|
6
|
+
export const LAYOUT_TYPES = ['1x1', '2x1', '1x2', '2x2'];
|
|
7
|
+
/** Minimal size of a Column or of a Row of the Grid, in percent of the Grid. */
|
|
8
|
+
export const MIN_CELL_SIZE = 15;
|
|
9
|
+
/** Maximal size of a Column or of a Row of the Grid, in percent of the Grid. */
|
|
10
|
+
export const MAX_CELL_SIZE = 85;
|
|
11
|
+
/**
|
|
12
|
+
* The Components that can be displayed in a Cell of the Grid.
|
|
13
|
+
* To make a new Component available to the user, it is enough to add it to this list
|
|
14
|
+
* (and to add its Element to the Grid in the HTML of the application).
|
|
15
|
+
*/
|
|
16
|
+
export const AVAILABLE_CELL_COMPONENTS = [
|
|
17
|
+
{ id: 'map-2d', tagName: 'girafe-map-2d', label: '2D Map' },
|
|
18
|
+
{ id: 'map-3d', tagName: 'girafe-map-3d', label: '3D Map' }
|
|
19
|
+
];
|
|
20
|
+
export function isLayoutType(value) {
|
|
21
|
+
return LAYOUT_TYPES.includes(value);
|
|
22
|
+
}
|
|
23
|
+
export function isCellComponent(value) {
|
|
24
|
+
return AVAILABLE_CELL_COMPONENTS.some((component) => component.id === value);
|
|
25
|
+
}
|
|
26
|
+
/** The number of columns and of rows of a Layout. */
|
|
27
|
+
export function getGridSize(type) {
|
|
28
|
+
const [columns, rows] = type.split('x').map(Number);
|
|
29
|
+
return { columns, rows };
|
|
30
|
+
}
|
|
31
|
+
/** The sizes, in percent, of the equally distributed columns and rows of a Layout. */
|
|
32
|
+
export function getDefaultSizes(type) {
|
|
33
|
+
const { columns, rows } = getGridSize(type);
|
|
34
|
+
return {
|
|
35
|
+
columns: new Array(columns).fill(100 / columns),
|
|
36
|
+
rows: new Array(rows).fill(100 / rows)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Distributes the Components on the Cells of a Layout.
|
|
41
|
+
* The Components that are already placed keep their Cell as long as it still exists,
|
|
42
|
+
* and the Cells that are added by the new Layout are filled with the Components
|
|
43
|
+
* that are not placed anywhere yet.
|
|
44
|
+
*/
|
|
45
|
+
export function distributeCells(type, currentCells) {
|
|
46
|
+
const { columns, rows } = getGridSize(type);
|
|
47
|
+
const cellCount = columns * rows;
|
|
48
|
+
const cells = currentCells.slice(0, cellCount);
|
|
49
|
+
const unplacedComponents = AVAILABLE_CELL_COMPONENTS.map((component) => component.id).filter((id) => !cells.includes(id));
|
|
50
|
+
while (cells.length < cellCount) {
|
|
51
|
+
cells.push(unplacedComponents.shift() ?? null);
|
|
52
|
+
}
|
|
53
|
+
return cells;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The Layout of the Map Grid: which Layout is displayed, which Component is displayed
|
|
57
|
+
* in each of its Cells, and the sizes of its columns and rows (in percent),
|
|
58
|
+
* which the user can change by dragging the splitters.
|
|
59
|
+
*
|
|
60
|
+
* The Cells are indexed row by row: in a 2x2 Layout, the Cell 0 is the top-left one,
|
|
61
|
+
* the Cell 1 the top-right one, the Cell 2 the bottom-left one and the Cell 3 the bottom-right one.
|
|
62
|
+
*/
|
|
63
|
+
export default class LayoutState {
|
|
64
|
+
type = '1x1';
|
|
65
|
+
cells = ['map-2d'];
|
|
66
|
+
sizes = { columns: [100], rows: [100] };
|
|
67
|
+
}
|
package/tools/state/state.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import MapPosition from './mapposition.js';
|
|
2
2
|
import GlobeState from './globe.js';
|
|
3
|
+
import LayoutState from './layout.js';
|
|
3
4
|
import type Basemap from '../../models/basemaps/basemap.js';
|
|
4
5
|
import type ThemeLayer from '../../models/layers/themelayer.js';
|
|
5
6
|
import type OlGeomLineString from 'ol/geom/LineString.js';
|
|
@@ -124,6 +125,7 @@ export default class State {
|
|
|
124
125
|
treeview: TreeviewConfig;
|
|
125
126
|
print: PrintConfig;
|
|
126
127
|
globe: GlobeState;
|
|
128
|
+
layout: LayoutState;
|
|
127
129
|
theme: Theme | null;
|
|
128
130
|
selection: ObjectSelection;
|
|
129
131
|
infobox: {
|
package/tools/state/state.js
CHANGED
|
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
// SPDX-License-Identifier: Apache-2.0
|
|
8
8
|
import MapPosition from './mapposition.js';
|
|
9
9
|
import GlobeState from './globe.js';
|
|
10
|
+
import LayoutState from './layout.js';
|
|
10
11
|
import { BrainSerialize } from './brain/decorators.js';
|
|
11
12
|
import LayersConfig from './layersConfig.js';
|
|
12
13
|
import ObjectSelection from './objectselection.js';
|
|
@@ -90,6 +91,10 @@ export default class State {
|
|
|
90
91
|
};
|
|
91
92
|
// Current 3D-Globe state
|
|
92
93
|
globe = new GlobeState();
|
|
94
|
+
// Current Layout of the Map Grid
|
|
95
|
+
// Note: it must stay declared after <globe>, so that a legacy globe.display coming from
|
|
96
|
+
// an old shared state is translated into a layout before this one is deserialized.
|
|
97
|
+
layout = new LayoutState();
|
|
93
98
|
// TODO REG : What is this used for?
|
|
94
99
|
// Is it the default theme configured in the user preferences?
|
|
95
100
|
// Do we really need this?
|
|
@@ -142,6 +147,9 @@ __decorate([
|
|
|
142
147
|
__decorate([
|
|
143
148
|
BrainSerialize
|
|
144
149
|
], State.prototype, "globe", void 0);
|
|
150
|
+
__decorate([
|
|
151
|
+
BrainSerialize
|
|
152
|
+
], State.prototype, "layout", void 0);
|
|
145
153
|
__decorate([
|
|
146
154
|
BrainSerialize
|
|
147
155
|
], State.prototype, "selection", void 0);
|
|
@@ -10,6 +10,7 @@ declare class StateManager extends GirafeSingleton {
|
|
|
10
10
|
constructor(context: IGirafeContext);
|
|
11
11
|
initializeSingleton(): void;
|
|
12
12
|
private setDefaultValues;
|
|
13
|
+
private setDefaultLayout;
|
|
13
14
|
/**
|
|
14
15
|
* Get the language based on the following priority:
|
|
15
16
|
* 1. user preferences, 2. browser language, 3. app default language
|
|
@@ -4,6 +4,7 @@ import GirafeSingleton from '../../base/GirafeSingleton.js';
|
|
|
4
4
|
import State from './state.js';
|
|
5
5
|
import { getPropertyByPath } from '../utils/pathUtils.js';
|
|
6
6
|
import Brain from './brain/brain.js';
|
|
7
|
+
import { distributeCells, getDefaultSizes } from './layout.js';
|
|
7
8
|
class StateManager extends GirafeSingleton {
|
|
8
9
|
girafeState = new State();
|
|
9
10
|
stateProxy;
|
|
@@ -28,8 +29,15 @@ class StateManager extends GirafeSingleton {
|
|
|
28
29
|
this.state.projection = config.map.srid;
|
|
29
30
|
this.state.language = this.decideLanguage();
|
|
30
31
|
this.state.interface.selectionComponent = config.interface.defaultSelectionComponent;
|
|
32
|
+
this.setDefaultLayout();
|
|
31
33
|
}
|
|
32
34
|
}
|
|
35
|
+
setDefaultLayout() {
|
|
36
|
+
const defaultLayout = this.context.configManager.Config.interface.defaultLayout;
|
|
37
|
+
this.state.layout.type = defaultLayout;
|
|
38
|
+
this.state.layout.cells = distributeCells(defaultLayout, this.state.layout.cells);
|
|
39
|
+
this.state.layout.sizes = getDefaultSizes(defaultLayout);
|
|
40
|
+
}
|
|
33
41
|
/**
|
|
34
42
|
* Get the language based on the following priority:
|
|
35
43
|
* 1. user preferences, 2. browser language, 3. app default language
|