Skip to content

Commit

Permalink
Support for terrainProvider in Cesium
Browse files Browse the repository at this point in the history
 - Now we can configure a terrainProvider
 - Support to intercept correct ray from camera to clicked point in feature info
 - defaultMapOptions added to localConfig as default. If present, it will be used to setup the mapOptions for the map.
 - Added to localConfig of product the demo terrainProvider
 - Throttling for mouse hover events in cesium map
  • Loading branch information
offtherailz committed Apr 4, 2017
1 parent 90c7e22 commit ebdb23d
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 22 deletions.
51 changes: 35 additions & 16 deletions web/client/components/map/cesium/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ var Cesium = require('../../../libs/cesium');
var React = require('react');
var ReactDOM = require('react-dom');
var ConfigUtils = require('../../../utils/ConfigUtils');
var ClickUtils = require('../../../utils/cesium/ClickUtils');
var assign = require('object-assign');
const {throttle} = require('lodash');

let CesiumMap = React.createClass({
propTypes: {
Expand Down Expand Up @@ -55,27 +57,15 @@ let CesiumMap = React.createClass({
timeline: false,
navigationHelpButton: false,
navigationInstructionsInitiallyVisible: false
}, this.props.mapOptions));
}, this.getMapOptions(this.props.mapOptions)));
map.imageryLayers.removeAll();
map.camera.moveEnd.addEventListener(this.updateMapInfoState);
this.hand = new Cesium.ScreenSpaceEventHandler(map.scene.canvas);
this.hand.setInputAction((movement) => {
this.onClick(map, movement);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

this.hand.setInputAction((movement) => {
if (this.props.onMouseMove && movement.endPosition) {
const cartesian = map.camera.pickEllipsoid(movement.endPosition, map.scene.globe.ellipsoid);
if (cartesian) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
this.props.onMouseMove({
y: cartographic.latitude * 180.0 / Math.PI,
x: cartographic.longitude * 180.0 / Math.PI,
crs: "EPSG:4326"
});
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.hand.setInputAction(throttle(this.onMouseMove.bind(this), 500), Cesium.ScreenSpaceEventType.MOUSE_MOVE);

map.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
Expand Down Expand Up @@ -104,21 +94,22 @@ let CesiumMap = React.createClass({
this.map.destroy();
},
onClick(map, movement) {

if (this.props.onClick && movement.position !== null) {
const cartesian = map.camera.pickEllipsoid(movement.position, map.scene.globe.ellipsoid);
if (cartesian) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let cartographic = ClickUtils.getMouseXYZ(map, movement) || Cesium.Cartographic.fromCartesian(cartesian);
const latitude = cartographic.latitude * 180.0 / Math.PI;
const longitude = cartographic.longitude * 180.0 / Math.PI;

const y = ((90.0 - latitude) / 180.0) * this.props.standardHeight * (this.props.zoom + 1);
const x = ((180.0 + longitude) / 360.0) * this.props.standardWidth * (this.props.zoom + 1);

this.props.onClick({
pixel: {
x: x,
y: y
},
height: this.props.mapOptions && this.props.mapOptions.terrainProvider ? cartographic.height : undefined,
latlng: {
lat: latitude,
lng: longitude
Expand All @@ -128,6 +119,34 @@ let CesiumMap = React.createClass({
}
}
},
onMouseMove(movement) {
if (this.props.onMouseMove && movement.endPosition) {
const cartesian = this.map.camera.pickEllipsoid(movement.endPosition, this.map.scene.globe.ellipsoid);
if (cartesian) {
const cartographic = ClickUtils.getMouseXYZ(this.map, movement) || Cesium.Cartographic.fromCartesian(cartesian);
this.props.onMouseMove({
y: cartographic.latitude * 180.0 / Math.PI,
x: cartographic.longitude * 180.0 / Math.PI,
crs: "EPSG:4326"
});
}
}
},
getMapOptions(rawOptions) {
let overrides = {};
if (rawOptions.terrainProvider) {
let {type, ...tpOptions} = rawOptions.terrainProvider;
switch (type) {
case "cesium": {
overrides.terrainProvider = new Cesium.CesiumTerrainProvider(tpOptions);
break;
}
default:
break;
}
}
return assign({}, rawOptions, overrides);
},
getCenter() {
const center = this.map.camera.positionCartographic;
return {
Expand Down
33 changes: 27 additions & 6 deletions web/client/components/map/cesium/__tests__/Map-test-chrome.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
var React = require('react');
var ReactDOM = require('react-dom');
var CesiumMap = require('../Map.jsx');
var CesiumLayer = require('../Layer.jsx');
var expect = require('expect');
var Cesium = require('../../../../libs/cesium');
const React = require('react');
const ReactDOM = require('react-dom');
const CesiumMap = require('../Map.jsx');
const CesiumLayer = require('../Layer.jsx');
const expect = require('expect');
const Cesium = require('../../../../libs/cesium');

require('../../../../utils/cesium/Layers');
require('../plugins/OSMLayer');
Expand Down Expand Up @@ -121,6 +121,27 @@ describe('CesiumMap', () => {
)
});
});
it('check mouse click handler', (done) => {
const testHandlers = {
handler: () => {}
};
var spy = expect.spyOn(testHandlers, 'handler');

const map = ReactDOM.render(
<CesiumMap
center={{y: 43.9, x: 10.3}}
zoom={11}
onClick={testHandlers.handler}
/>
, document.getElementById("container"));
expect(map.map).toExist();
map.onClick(map.map, {position: {x: 100, y: 100 }});
setTimeout(() => {
expect(spy.calls.length).toEqual(1);
expect(spy.calls[0].arguments.length).toEqual(1);
done();
}, 800);
});

it('check if the map changes when receive new props', () => {
let map = ReactDOM.render(
Expand Down
9 changes: 9 additions & 0 deletions web/client/localConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
"ignoreMobileCss": true,
"useAuthenticationRules": true,
"themePrefix": "ms2",
"defaultMapOptions": {
"cesium": {
"terrainProvider": {
"type": "cesium",
"url": "https://assets.agi.com/stk-terrain/world",
"requestVertexNormals": true
}
}
},
"authenticationRules": [{
"urlPattern": ".*geostore.*",
"method": "basic"
Expand Down
8 changes: 8 additions & 0 deletions web/client/plugins/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Spinner = require('react-spinkit');
require('./map/css/map.css');

const Message = require('../components/I18N/Message');
const ConfigUtils = require('../utils/ConfigUtils');
const {isString} = require('lodash');
let plugins;
/**
Expand Down Expand Up @@ -122,6 +123,7 @@ const MapPlugin = React.createClass({
loadingError: React.PropTypes.string,
tools: React.PropTypes.array,
options: React.PropTypes.object,
mapOptions: React.PropTypes.object,
toolsOptions: React.PropTypes.object,
actions: React.PropTypes.object,
features: React.PropTypes.array
Expand All @@ -135,6 +137,7 @@ const MapPlugin = React.createClass({
loadingSpinner: true,
tools: ["measurement", "locate", "overview", "scalebar", "draw", "highlight"],
options: {},
mapOptions: {},
toolsOptions: {
measurement: {},
locate: {},
Expand Down Expand Up @@ -183,6 +186,10 @@ const MapPlugin = React.createClass({
}
return tool[this.props.mapType] || tool;
},
getMapOptions() {
return this.props.mapOptions && this.props.mapOptions[this.props.mapType] ||
ConfigUtils.getConfigProp("defaultMapOptions") && ConfigUtils.getConfigProp("defaultMapOptions")[this.props.mapType];
},
renderLayers() {
const projection = this.props.map.projection || 'EPSG:3857';
return this.props.layers.map((layer, index) => {
Expand Down Expand Up @@ -224,6 +231,7 @@ const MapPlugin = React.createClass({
return (
<plugins.Map id="map"
{...this.props.options}
mapOptions={this.getMapOptions()}
{...this.props.map}
zoomControl={this.props.zoomControl}>
{this.renderLayers()}
Expand Down
51 changes: 51 additions & 0 deletions web/client/utils/cesium/ClickUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
var Cesium = require('../../libs/cesium');
const getCartesian = function(viewer, event) {
if (event.position !== null) {
const scene = viewer.scene;
const ellipsoid = scene._globe.ellipsoid;
const cartesian = scene._camera.pickEllipsoid(event.position, ellipsoid);
return cartesian;
}
};
const getMouseXYZ = (viewer, event) => {
var scene = viewer.scene;
if (!event.position) {
return null;
}
const ray = viewer.camera.getPickRay(event.position);
const position = viewer.scene.globe.pick(ray, viewer.scene);
const ellipsoid = scene._globe.ellipsoid;
if (Cesium.defined(position)) {
const cartographic = ellipsoid.cartesianToCartographic(position);
// const height = cartographic.height;
const cartesian = getCartesian(viewer, event);
if (cartesian) {
cartographic.height = scene._globe.getHeight(cartographic);
cartographic.cartesian = cartesian;
cartographic.position = position;
}
return cartographic;
}
return null;
};

const getMouseTile = (viewer, event) => {
const scene = viewer.scene;
if (!event.position) {
return null;
}
const ray = viewer.camera.getPickRay(event.position);
return viewer.scene.globe.pickTile(ray, scene);
};

module.exports = {
getMouseXYZ,
getMouseTile
};

0 comments on commit ebdb23d

Please sign in to comment.