Skip to content

Commit

Permalink
#8706 Restore multiple features selection on map click in 3D viewer (#…
Browse files Browse the repository at this point in the history
…8750)

* restore multiple features selection on map click in 3D viewer

* add bring to front on default style for points
  • Loading branch information
allyoucanmap authored Oct 31, 2022
1 parent 6d7ad1f commit 8447568
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 35 deletions.
8 changes: 6 additions & 2 deletions build/testConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ module.exports = ({browsers = [ 'ChromeHeadless' ], files, path, testFile, singl

basePath,

files,
files: [
...files,
// add all assets needed for Cesium library
{ pattern: './node_modules/cesium/Source/**/*', included: false }
],

plugins: [
require('karma-chrome-launcher'),
Expand Down Expand Up @@ -150,7 +154,7 @@ module.exports = ({browsers = [ 'ChromeHeadless' ], files, path, testFile, singl
}),
new webpack.DefinePlugin({
// Define relative base path in cesium for loading assets
'CESIUM_BASE_URL': JSON.stringify(nodePath.join(basePath, 'node_modules', 'cesium', 'Source'))
'CESIUM_BASE_URL': JSON.stringify('base/node_modules/cesium/Source')
}),
VERSION_INFO_DEFINE_PLUGIN,
// it's not possible to load directly from the module name `cesium/Build/Cesium/Widgets/widgets.css`
Expand Down
43 changes: 29 additions & 14 deletions web/client/components/map/cesium/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,22 +316,37 @@ class CesiumMap extends React.Component {
};

getIntersectedFeatures = (map, position) => {
// we can use pick so the only first intersect feature will be returned
// this is more intuitive for uses such as get feature info
const feature = map.scene.drillPick(position).find((aFeature) => {
// for consistency with 2D view we allow to drill pick through the first feature
// and intersect all the features behind
const features = map.scene.drillPick(position).filter((aFeature) => {
return !(aFeature?.id?.entityCollection?.owner?.queryable === false);
});
if (feature instanceof Cesium.Cesium3DTileFeature && feature?.tileset?.msId) {
const msId = feature.tileset.msId;
// 3d tile feature does not contain a geometry in the Cesium3DTileFeature class
// it has content but refers to the whole tile model
const propertyNames = feature.getPropertyNames();
const properties = Object.fromEntries(propertyNames.map(key => [key, feature.getProperty(key)]));
return [{ id: msId, features: [{ type: 'Feature', properties, geometry: null }] }];
} else if (feature?.id instanceof Cesium.Entity && feature.id.id && feature.id.properties) {
const {properties: {propertyNames}, entityCollection: {owner: {name}}} = feature.id;
const props = Object.fromEntries(propertyNames.map(key => [key, feature.id.properties[key].getValue(0)]));
return [{ id: name, features: [{ type: 'Feature', properties: props, id: feature?.id?.id, geometry: null }] }];
if (features) {
const groupIntersectedFeatures = features.reduce((acc, feature) => {
let msId;
let properties;
if (feature instanceof Cesium.Cesium3DTileFeature && feature?.tileset?.msId) {
msId = feature.tileset.msId;
// 3d tile feature does not contain a geometry in the Cesium3DTileFeature class
// it has content but refers to the whole tile model
const propertyNames = feature.getPropertyNames();
properties = Object.fromEntries(propertyNames.map(key => [key, feature.getProperty(key)]));
} else if (feature?.id instanceof Cesium.Entity && feature.id.id && feature.id.properties) {
const {properties: {propertyNames}, entityCollection: {owner: {name}}} = feature.id;
properties = Object.fromEntries(propertyNames.map(key => [key, feature.id.properties[key].getValue(0)]));
msId = name;
}
if (!properties || !msId) {
return acc;
}
return {
...acc,
[msId]: acc[msId]
? [...acc[msId], { type: 'Feature', properties, geometry: null }]
: [{ type: 'Feature', properties, geometry: null }]
};
}, []);
return Object.keys(groupIntersectedFeatures).map(id => ({ id, features: groupIntersectedFeatures[id] }));
}
return [];
}
Expand Down
133 changes: 117 additions & 16 deletions web/client/components/map/cesium/__tests__/Map-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
createRegisterHooks, GET_PIXEL_FROM_COORDINATES_HOOK, GET_COORDINATES_FROM_PIXEL_HOOK
} from '../../../../utils/MapUtils';
import { act } from 'react-dom/test-utils';

import { simulateClick } from './CesiumSimulate';
import { waitFor } from '@testing-library/react';
import '../../../../utils/cesium/Layers';
import '../plugins/OSMLayer';

Expand Down Expand Up @@ -226,30 +227,130 @@ describe('CesiumMap', () => {
}, 800);
});
it('click on layer should return intersected features', (done) => {
const testHandlers = {
handler: () => {}
};
const spy = expect.spyOn(testHandlers, 'handler');

let ref;
act(() => {
ReactDOM.render(
<CesiumMap
ref={value => { ref = value; } }
center={{y: 43.9, x: 10.3}}
zoom={11}
onClick={testHandlers.handler}
/>
onClick={({ intersectedFeatures }) => {
try {
expect(intersectedFeatures).toEqual(
[
{
id: 'vector',
features: [
{
type: 'Feature', properties: { category: 'area' },
geometry: null
},
{
type: 'Feature', properties: { category: 'boundary' },
geometry: null
}
]
}
]
);
} catch (e) {
done(e);
}
done();
}}
>
<CesiumLayer
type="vector"
options={{
id: 'vector',
visibility: true,
features: [
{
"type": "Feature",
"properties": {
"category": "boundary"
},
"geometry": {
"coordinates": [
[
[
1.0975911519593637,
48.583411572759644
],
[
1.0975911519593637,
38.03615349112002
],
[
19.43550678615742,
38.03615349112002
],
[
19.43550678615742,
48.583411572759644
],
[
1.0975911519593637,
48.583411572759644
]
]
],
"type": "Polygon"
}
},
{
"type": "Feature",
"properties": {
"category": "area"
},
"geometry": {
"coordinates": [
[
[
1.0975911519593637,
48.583411572759644
],
[
1.0975911519593637,
38.03615349112002
],
[
19.43550678615742,
38.03615349112002
],
[
19.43550678615742,
48.583411572759644
],
[
1.0975911519593637,
48.583411572759644
]
]
],
"type": "Polygon"
}
}
]
}}
/>
</CesiumMap>
, document.getElementById("container"));
});
expect(ref.map).toBeTruthy();
ref.onClick(ref.map, {position: {x: 100, y: 100 }});
setTimeout(() => {
expect(spy.calls.length).toEqual(1);
expect(spy.calls[0].arguments.length).toEqual(1);
expect(spy.calls[0].arguments[0].intersectedFeatures).toEqual([]);
done();
}, 800);
waitFor(() => expect(ref.map.dataSourceDisplay.ready).toBe(true))
.then(() => {
expect(ref.map.dataSources.length).toBe(1);
const dataSource = ref.map.dataSources.get(0);
expect(dataSource).toBeTruthy();
expect(dataSource.entities.values.length).toBe(2);
const mapCanvas = ref.map.canvas;
const { width, height } = mapCanvas.getBoundingClientRect();
simulateClick(mapCanvas, {
clientX: width / 2,
clientY: height / 2
});
})
.catch(done);
});
it('check if the map changes when receive new props', () => {
let ref;
Expand Down
2 changes: 1 addition & 1 deletion web/client/components/map/cesium/plugins/VectorLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {

const createLayer = (options, map) => {

let dataSource = new Cesium.GeoJsonDataSource();
let dataSource = new Cesium.GeoJsonDataSource(options?.id);

const features = flattenFeatures(options?.features || [], ({ style, ...feature }) => feature);
const collection = {
Expand Down
3 changes: 2 additions & 1 deletion web/client/utils/VectorStyleUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,8 @@ export function applyDefaultStyleToLayer(layer) {
strokeOpacity: 1,
strokeWidth: 2,
wellKnownName: 'Circle',
radius: 10
radius: 10,
msBringToFront: true
}
]
},
Expand Down
3 changes: 2 additions & 1 deletion web/client/utils/__tests__/VectorStyleUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,8 @@ describe("VectorStyleUtils ", () => {
strokeOpacity: 1,
strokeWidth: 2,
wellKnownName: 'Circle',
radius: 10
radius: 10,
msBringToFront: true
}
]
},
Expand Down

0 comments on commit 8447568

Please sign in to comment.