Skip to content

Commit 7e66b41

Browse files
authored
Fix #2661 First implementation of map widget (#2721)
1 parent 35b2696 commit 7e66b41

42 files changed

Lines changed: 1251 additions & 27 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
"redux-thunk": "0.1.0",
182182
"redux-undo": "0.5.0",
183183
"reselect": "2.5.1",
184+
"resize-observer-polyfill": "1.5.0",
184185
"rxjs": "5.1.1",
185186
"screenfull": "3.1.0",
186187
"shpjs": "3.4.2",

utility/translations/findMissingTranslations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,6 @@ files.forEach(file => {
101101
if (fail) {
102102
throw Error("i18n files failed");
103103
}
104-
log('## mandatory translations checks passed!! ##');
104+
log('## mandatory translations checks passed!! ##\n');
105105

106106

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* Copyright 2018, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
const React = require('react');
9+
const PropTypes = require('prop-types');
10+
const { isString } = require('lodash');
11+
12+
/**
13+
* Base map component that renders a map.
14+
* It is implementation independent.
15+
* The implementation of the layer is provided by the `plugins` property
16+
* @prop {string} id the id of the map div
17+
* @prop {object} options. Options to pass to the map component (generically constant)
18+
* @prop {object} map the map properties (projection...) This is generically the dynamic part of the map options.
19+
* @prop {object[]} layers the layers to add to the map
20+
* @prop {object} plugins specific implementation of the components to render.
21+
* Must contain implementations for:
22+
* - Map React component for Map
23+
* - Layer React component for Layer
24+
* - Feature (optional) React component for vector Feature
25+
* - tools (optional) any support tool you want to use
26+
* @prop {array} tools. A list of tools (string name or object with `name` and other options as attribute) to add to the map.
27+
* @prop {object} eventHandlers handlers for map events
28+
* Each tool must be implemented in plugins.tools
29+
*
30+
*/
31+
class BaseMap extends React.Component {
32+
static propTypes = {
33+
id: PropTypes.string,
34+
options: PropTypes.object,
35+
map: PropTypes.object,
36+
mapStateSource: PropTypes.string,
37+
eventHandlers: PropTypes.object,
38+
layers: PropTypes.array,
39+
plugins: PropTypes.any,
40+
tools: PropTypes.array,
41+
getLayerProps: PropTypes.func
42+
};
43+
44+
static defaultProps = {
45+
id: '__base_map__',
46+
options: {},
47+
map: {},
48+
tools: [],
49+
eventHandlers: {
50+
onMapViewChanges: () => {},
51+
onClick: () => {},
52+
onMouseMove: () => {},
53+
onLayerLoading: () => {},
54+
onLayerError: () => {}
55+
}
56+
};
57+
58+
getTool = (tool) => {
59+
const { plugins } = this.props;
60+
if (isString(tool)) {
61+
return {
62+
name: tool,
63+
impl: plugins.tools[tool]
64+
};
65+
}
66+
return {
67+
name: tool.name,
68+
impl: plugins.tools[tool.name],
69+
...tool
70+
};
71+
};
72+
73+
renderLayers = () => {
74+
const projection = this.props.map.projection || 'EPSG:3857';
75+
const { plugins } = this.props;
76+
const { Layer } = plugins;
77+
return this.props.layers.map((layer, index) => {
78+
return (
79+
<Layer
80+
type={layer.type}
81+
srs={projection}
82+
position={index}
83+
key={layer.id || layer.name}
84+
options={layer}
85+
>
86+
{this.renderLayerContent(layer, projection)}
87+
</Layer>
88+
);
89+
});
90+
};
91+
92+
renderLayerContent = (layer, projection) => {
93+
if (layer.features && layer.type === "vector") {
94+
const { plugins } = this.props;
95+
const { Feature } = plugins;
96+
return layer.features.map((feature) => {
97+
return (
98+
<Feature
99+
key={feature.id}
100+
msId={feature.id}
101+
type={feature.type}
102+
crs={projection}
103+
geometry={feature.geometry}
104+
msId={feature.id}
105+
featuresCrs={layer.featuresCrs || 'EPSG:4326'}
106+
// FEATURE STYLE OVERWRITE LAYER STYLE
107+
layerStyle={layer.style}
108+
style={feature.style || layer.style || null}
109+
properties={feature.properties} />
110+
);
111+
});
112+
}
113+
return null;
114+
};
115+
116+
renderTools = () => {
117+
return this.props.tools.map((tool) => {
118+
const {impl: Tool, name, ...options} = this.getTool(tool);
119+
return <Tool key={name} {...options} />;
120+
});
121+
};
122+
123+
render() {
124+
const {plugins} = this.props;
125+
const {Map} = plugins;
126+
if (this.props.map) {
127+
return (
128+
<Map
129+
id={this.props.id}
130+
zoomControl={false}
131+
center={{ x: 0, y: 0 }}
132+
zoom={1}
133+
mapStateSource={this.props.mapStateSource || this.props.id}
134+
{...this.props.options}
135+
{...this.props.map}
136+
{...this.props.eventHandlers}
137+
>
138+
{this.renderLayers()}
139+
{this.renderTools()}
140+
</Map>
141+
);
142+
}
143+
return null;
144+
}
145+
}
146+
module.exports = BaseMap;
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* Copyright 2018, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
const React = require('react');
9+
const ReactDOM = require('react-dom');
10+
const expect = require('expect');
11+
12+
const BaseMap = require('../BaseMap');
13+
const mapType = require('../enhancers/mapType');
14+
const TestMap = mapType(BaseMap);
15+
16+
const LAYER_OSM = {
17+
"id": "mapnik__1",
18+
"group": "background",
19+
"source": "osm",
20+
"name": "mapnik",
21+
"title": "Open Street Map",
22+
"type": "osm",
23+
"visibility": true,
24+
"singleTile": false,
25+
"dimensions": [],
26+
"hideLoading": false,
27+
"handleClickOnLayer": false
28+
};
29+
const VECTOR_SAMPLE = {
30+
"id": "annotations",
31+
"features": [
32+
{
33+
"type": "Feature",
34+
"properties": {
35+
"title": "Title",
36+
"id": "25cbbbb0-1625-11e8-a091-639e3ca0149f"
37+
},
38+
"geometry": {
39+
"type": "MultiPolygon",
40+
"coordinates": [
41+
[
42+
[
43+
[
44+
-9.272079296695848,
45+
25.633162709158384
46+
],
47+
[
48+
0.17443093439845475,
49+
38.01066790632649
50+
],
51+
[
52+
11.823370741927429,
53+
17.650189135909482
54+
],
55+
[
56+
-9.272079296695848,
57+
25.633162709158384
58+
]
59+
]
60+
]
61+
]
62+
},
63+
"style": {
64+
"type": "MultiPolygon",
65+
"MultiPolygon": {
66+
"color": "#ffcc33",
67+
"opacity": 1,
68+
"weight": 3,
69+
"fillColor": "#ffffff",
70+
"fillOpacity": 0.2,
71+
"editing": {
72+
"fill": 1
73+
}
74+
},
75+
"Polygon": {
76+
"color": "#ffcc33",
77+
"opacity": 1,
78+
"weight": 3,
79+
"fillColor": "#ffffff",
80+
"fillOpacity": 0.2,
81+
"editing": {
82+
"fill": 1
83+
}
84+
},
85+
"highlight": false
86+
}
87+
}
88+
],
89+
"name": "Annotations",
90+
"style": {
91+
"type": "MultiPolygon",
92+
"MultiPolygon": {
93+
"color": "#ffcc33",
94+
"opacity": 1,
95+
"weight": 3,
96+
"fillColor": "#ffffff",
97+
"fillOpacity": 0.2,
98+
"editing": {
99+
"fill": 1
100+
}
101+
},
102+
"Polygon": {
103+
"color": "#ffcc33",
104+
"opacity": 1,
105+
"weight": 3,
106+
"fillColor": "#ffffff",
107+
"fillOpacity": 0.2,
108+
"editing": {
109+
"fill": 1
110+
}
111+
}
112+
},
113+
"type": "vector",
114+
"visibility": true,
115+
"singleTile": false,
116+
"dimensions": [
117+
118+
],
119+
"hideLoading": true,
120+
"handleClickOnLayer": true
121+
};
122+
const SAMPLE_LAYERS_1 = [LAYER_OSM, VECTOR_SAMPLE];
123+
124+
window.CESIUM_BASE_URL = "web/client/libs/Cesium/Build/Cesium";
125+
126+
describe('BaseMap', () => {
127+
beforeEach((done) => {
128+
document.body.innerHTML = '<div id="container"></div>';
129+
setTimeout(done);
130+
});
131+
afterEach((done) => {
132+
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
133+
document.body.innerHTML = '';
134+
setTimeout(done);
135+
});
136+
it('test cesium map', () => {
137+
const map = ReactDOM.render(<TestMap mapType="cesium" id="myMap" layers={SAMPLE_LAYERS_1} />, document.getElementById("container"));
138+
expect(map).toExist();
139+
const el = ReactDOM.findDOMNode(map);
140+
expect(el).toExist();
141+
expect(el.id).toBe("myMap");
142+
expect(el.querySelector('canvas')).toExist();
143+
144+
});
145+
146+
});

0 commit comments

Comments
 (0)