diff --git a/web/client/actions/__tests__/tutorial-test.js b/web/client/actions/__tests__/tutorial-test.js index ce2b1b60b2..7d69a3042a 100644 --- a/web/client/actions/__tests__/tutorial-test.js +++ b/web/client/actions/__tests__/tutorial-test.js @@ -34,13 +34,15 @@ describe('Test the tutorial actions', () => { }); it('setupTutorial', () => { + const id = 'id'; const steps = 'steps'; const style = 'style'; const checkbox = 'checkbox'; const defaultStep = 'defaultStep'; - const retval = setupTutorial(steps, style, checkbox, defaultStep); + const retval = setupTutorial(id, steps, style, checkbox, defaultStep); expect(retval).toExist(); expect(retval.type).toBe(SETUP_TUTORIAL); + expect(retval.id).toBe(id); expect(retval.steps).toBe(steps); expect(retval.style).toBe(style); expect(retval.checkbox).toBe(checkbox); diff --git a/web/client/actions/tutorial.js b/web/client/actions/tutorial.js index e52cdcfec4..1217423966 100644 --- a/web/client/actions/tutorial.js +++ b/web/client/actions/tutorial.js @@ -20,9 +20,10 @@ function startTutorial() { }; } -function setupTutorial(steps, style, checkbox, defaultStep) { +function setupTutorial(id, steps, style, checkbox, defaultStep) { return { type: SETUP_TUTORIAL, + id, steps, style, checkbox, diff --git a/web/client/components/map/cesium/Map.jsx b/web/client/components/map/cesium/Map.jsx index 586348338a..640b2ad3c8 100644 --- a/web/client/components/map/cesium/Map.jsx +++ b/web/client/components/map/cesium/Map.jsx @@ -6,6 +6,7 @@ * LICENSE file in the root directory of this source tree. */ var Cesium = require('../../../libs/cesium'); +const Rx = require('rxjs'); var React = require('react'); var ReactDOM = require('react-dom'); var ConfigUtils = require('../../../utils/ConfigUtils'); @@ -69,10 +70,7 @@ let CesiumMap = React.createClass({ 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.subscribeClickEvent(map); this.hand.setInputAction(throttle(this.onMouseMove.bind(this), 500), Cesium.ScreenSpaceEventType.MOUSE_MOVE); map.camera.setView({ @@ -90,11 +88,7 @@ let CesiumMap = React.createClass({ if (this.props.mapOptions.navigationTools) { this.cesiumNavigation = window.CesiumNavigation; if (this.cesiumNavigation) { - this.cesiumNavigation.navigationInitialization(this.props.id, map, { - enableZoomControls: false, - enableDistanceLegend: false, - enableCompassOuterRing: false - }); + this.cesiumNavigation.navigationInitialization(this.props.id, map); } } }, @@ -108,11 +102,12 @@ let CesiumMap = React.createClass({ return false; }, componentWillUnmount() { + this.clickStream$.complete(); + this.pauserStream$.complete(); this.hand.destroy(); this.map.destroy(); }, onClick(map, movement) { - if (this.props.onClick && movement.position !== null) { const cartesian = map.camera.pickEllipsoid(movement.position, map.scene.globe.ellipsoid); let cartographic = ClickUtils.getMouseXYZ(map, movement) || cartesian && Cesium.Cartographic.fromCartesian(cartesian); @@ -236,6 +231,54 @@ let CesiumMap = React.createClass({ this.map.camera.setView(position); } }, + subscribeClickEvent(map) { + const samePosition = (m1, m2) => m1 && m2 && m1.x === m2.x && m1.y === m2.y; + const types = { + LEFT_UP: Cesium.ScreenSpaceEventType.LEFT_UP, + LEFT_DOWN: Cesium.ScreenSpaceEventType.LEFT_DOWN, + LEFT_CLICK: Cesium.ScreenSpaceEventType.LEFT_CLICK, + PINCH_START: Cesium.ScreenSpaceEventType.PINCH_START, + PINCH_END: Cesium.ScreenSpaceEventType.PINCH_END, + PINCH_MOVE: Cesium.ScreenSpaceEventType.PINCH_MOVE + }; + const clickStream$ = new Rx.Subject(); + const pauserStream$ = new Rx.Subject(); + Object.keys(types).forEach((type) => this.hand.setInputAction((movement) => { + pauserStream$.next({type: types[type], movement}); + clickStream$.next({type: types[type], movement}); + }, types[type])); + + /* + * trigger onClick only when LEFT_CLICK that follow a LEFT_DOWN at the same position. + * Every other mouse event before the LEFT_CLICK will not trigger the onClick function (happens with multitouch devices from cesium). + * If a pinch event is ended, wait to start listening left clicks. This to skip the LEFT_UP,LEFT_DOWN, LEFT_CLICK sequence that cesium triggers after a pinch end, + * that othewise can not be distinguished from a normal click event. + */ + pauserStream$ + .filter( ev => ev.type === types.PINCH_END ) + .switchMap( () => Rx.Observable.of(true).concat(Rx.Observable.of(false).delay(500))) + .startWith(false) + .switchMap(paused => { + // pause is realized by mapping the click stream or an infinite stream + return paused ? Rx.Observable.never() : clickStream$; + }) + .filter( ev => ev.type === types.LEFT_DOWN ) + .switchMap(({movement}) => + clickStream$ + .filter( ev => ev.type === types.LEFT_CLICK ) + .takeUntil( + Rx.Observable.timer(500).merge( + clickStream$ + .filter( ev => + ev.type !== types.LEFT_UP && ev.type !== types.LEFT_CLICK + || ev.type === types.LEFT_UP && !samePosition(movement && movement.position, ev.movement && ev.movement.position) + ) + ) + ) + ).subscribe(({movement}) => this.onClick(map, movement)); + this.clickStream$ = clickStream$; + this.pauserStream$ = pauserStream$; + }, updateMapInfoState() { const center = this.getCenter(); const zoom = this.getZoomFromHeight(center.height); diff --git a/web/client/components/maps/modals/MetadataModal.jsx b/web/client/components/maps/modals/MetadataModal.jsx index d16cb0f1f6..4fbf1d50b1 100644 --- a/web/client/components/maps/modals/MetadataModal.jsx +++ b/web/client/components/maps/modals/MetadataModal.jsx @@ -291,9 +291,7 @@ const MetadataModal = React.createClass({ }, isMetadataChanged() { return this.props.map && ( - this.props.map.description !== undefined && this.props.metadata.description !== this.props.map.description || - this.props.map.name !== undefined && this.props.metadata.name !== this.props.map.name ); }, diff --git a/web/client/components/tutorial/Tutorial.jsx b/web/client/components/tutorial/Tutorial.jsx index dd5af46d7c..06f699eb44 100644 --- a/web/client/components/tutorial/Tutorial.jsx +++ b/web/client/components/tutorial/Tutorial.jsx @@ -77,7 +77,7 @@ const Tutorial = React.createClass({ return { toggle: false, status: 'run', - preset: 'map', + preset: 'default_tutorial', presetList: {}, introPosition: (window.innerHeight - 348) / 2, rawSteps: [], @@ -121,7 +121,7 @@ const Tutorial = React.createClass({ componentWillMount() { let rawSteps = this.props.rawSteps.length > 0 ? this.props.rawSteps : this.props.presetList[this.props.preset] || []; let checkbox = this.props.showCheckbox ?
:
; - this.props.actions.onSetup(rawSteps, this.props.introStyle, checkbox, this.props.defaultStep); + this.props.actions.onSetup('default', rawSteps, this.props.introStyle, checkbox, this.props.defaultStep); }, componentWillUpdate(newProps) { if (this.props.steps.length > 0) { diff --git a/web/client/components/tutorial/__tests__/Tutorial-test.jsx b/web/client/components/tutorial/__tests__/Tutorial-test.jsx index 8a8b9f4982..2e02f94ad7 100644 --- a/web/client/components/tutorial/__tests__/Tutorial-test.jsx +++ b/web/client/components/tutorial/__tests__/Tutorial-test.jsx @@ -87,7 +87,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith([], {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', [], {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); @@ -120,7 +120,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith(presetList.test, {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', presetList.test, {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); @@ -164,7 +164,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith(rawSteps, {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', rawSteps, {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); diff --git a/web/client/epics/tutorial.js b/web/client/epics/tutorial.js index f6579ac075..57033ac614 100644 --- a/web/client/epics/tutorial.js +++ b/web/client/epics/tutorial.js @@ -7,8 +7,13 @@ */ const Rx = require('rxjs'); -const {START_TUTORIAL, closeTutorial} = require('../actions/tutorial'); +const {START_TUTORIAL, closeTutorial, setupTutorial} = require('../actions/tutorial'); +const {CHANGE_MAP_VIEW} = require('../actions/map'); const {TOGGLE_3D} = require('../actions/globeswitcher'); +const preset = require('../plugins/tutorial/preset'); +const defaultRegex = /\/(viewer)\/(\w+)\/(\d+)/; +const findMapType = path => path.match(defaultRegex) && path.replace(defaultRegex, "$2"); +import { UPDATE_LOCATION } from 'react-router-redux'; /** * Closes the tutorial if 3D button has been toggled @@ -22,6 +27,30 @@ const closeTutorialEpic = (action$) => .audit(() => action$.ofType(TOGGLE_3D)) .switchMap( () => Rx.Observable.of(closeTutorial())); +/** + * Setup new steps based on the current maptype + * @memberof epics.tutorial + * @param {external:Observable} action$ manages `UPDATE_LOCATION` + * @return {external:Observable} + */ + +const switchTutorialEpic = (action$, store) => + action$.ofType(UPDATE_LOCATION) + .audit(() => action$.ofType(CHANGE_MAP_VIEW)) + .filter(action => + action.payload + && action.payload.pathname + && action.payload.pathname.match(defaultRegex)) + .switchMap( (action) => { + const path = findMapType(action.payload.pathname); + const browser = store.getState().browser; + const mobile = browser && browser.mobile ? '_mobile' : ''; + return Rx.Observable.of(preset[path + mobile + '_tutorial'] ? + setupTutorial(path + mobile, preset[path + mobile + '_tutorial']) : + setupTutorial('default' + mobile, preset['default' + mobile + '_tutorial']) + ); + }); + /** * Epics for Tutorial * @name epics.tutorial @@ -29,5 +58,6 @@ const closeTutorialEpic = (action$) => */ module.exports = { - closeTutorialEpic + closeTutorialEpic, + switchTutorialEpic }; diff --git a/web/client/libs/cesium-navigation/cesium-navigation.css b/web/client/libs/cesium-navigation/cesium-navigation.css index 257b02a88c..6518c8a90d 100644 --- a/web/client/libs/cesium-navigation/cesium-navigation.css +++ b/web/client/libs/cesium-navigation/cesium-navigation.css @@ -137,7 +137,8 @@ height: 95px; fill: #68ADFE; } -#distanceLegendDiv > .navigation-controls > div:nth-child(2) { +/*#distanceLegendDiv > > div:nth-child(2) {*/ +#distanceLegendDiv .navigation-controls { display: none; } diff --git a/web/client/localConfig.json b/web/client/localConfig.json index 175b7a8f0e..2cb20b927e 100644 --- a/web/client/localConfig.json +++ b/web/client/localConfig.json @@ -78,7 +78,7 @@ }, "Home", "TOC", { "name": "Tutorial", "cfg": { - "preset": "mapMobile" + "preset": "default_mobile_tutorial" } }, { "name": "Settings", diff --git a/web/client/plugins/GlobeViewSwitcher.jsx b/web/client/plugins/GlobeViewSwitcher.jsx index 0df23e0d9c..4ecefc772f 100644 --- a/web/client/plugins/GlobeViewSwitcher.jsx +++ b/web/client/plugins/GlobeViewSwitcher.jsx @@ -40,7 +40,7 @@ module.exports = { GlobeViewSwitcherPlugin: assign(GlobeViewSwitcher, { Toolbar: { name: '3d', - position: 5, + position: 10, alwaysVisible: true, tool: true, priority: 1 diff --git a/web/client/plugins/Tutorial.jsx b/web/client/plugins/Tutorial.jsx index fd7f8fb8a3..d4959ef8f4 100644 --- a/web/client/plugins/Tutorial.jsx +++ b/web/client/plugins/Tutorial.jsx @@ -16,7 +16,7 @@ const I18N = require('../components/I18N/I18N'); const {Glyphicon} = require('react-bootstrap'); const {createSelector} = require('reselect'); const {tutorialSelector} = require('../selectors/tutorial'); -const {closeTutorialEpic} = require('../epics/tutorial'); +const {closeTutorialEpic, switchTutorialEpic} = require('../epics/tutorial'); /* ////////////////////////// @@ -217,6 +217,7 @@ module.exports = { tutorial: require('../reducers/tutorial') }, epics: { - closeTutorialEpic + closeTutorialEpic, + switchTutorialEpic } }; diff --git a/web/client/plugins/tutorial/preset.js b/web/client/plugins/tutorial/preset.js index f3cec401ff..3258651116 100644 --- a/web/client/plugins/tutorial/preset.js +++ b/web/client/plugins/tutorial/preset.js @@ -7,7 +7,9 @@ */ module.exports = { - map: require('./preset/map'), - home: require('./preset/home'), - mapMobile: require('./preset/mapMobile') + default_tutorial: require('./preset/default_tutorial'), + default_mobile_tutorial: require('./preset/default_mobile_tutorial'), + home_tutorial: require('./preset/home_tutorial'), + cesium_tutorial: require('./preset/cesium_tutorial'), + cesium_mobile_tutorial: require('./preset/cesium_mobile_tutorial') }; diff --git a/web/client/plugins/tutorial/preset/mapMobile.js b/web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js similarity index 84% rename from web/client/plugins/tutorial/preset/mapMobile.js rename to web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js index 1f630407b6..11cd5e0903 100644 --- a/web/client/plugins/tutorial/preset/mapMobile.js +++ b/web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js @@ -11,15 +11,23 @@ const I18N = require('../../../components/I18N/I18N'); const CesiumTooltip = require('../../../components/tutorial/steps/CesiumTooltip'); module.exports = [ - // remove comment to enable intro/autostart - /*{ - translation: 'intro', + { + translation: 'introCesium', selector: '#intro-tutorial' - },*/ + }, + { + title: , + text: , + selector: '#map .cesium-viewer' + }, { translation: 'drawerMenu', selector: '#drawer-menu-button' }, + { + translation: 'home', + selector: '#home-button' + }, { translation: 'searchButton', selector: '#search-help' @@ -27,15 +35,5 @@ module.exports = [ { translation: 'burgerMenu', selector: '#mapstore-burger-menu' - }, - { - title: , - text: , - selector: '#map .cesium-viewer', - position: 'bottom' - }, - { - translation: 'home', - selector: '#home-button' } ]; diff --git a/web/client/plugins/tutorial/preset/map.js b/web/client/plugins/tutorial/preset/cesium_tutorial.js similarity index 75% rename from web/client/plugins/tutorial/preset/map.js rename to web/client/plugins/tutorial/preset/cesium_tutorial.js index a4abfc6a8e..4c883295f6 100644 --- a/web/client/plugins/tutorial/preset/map.js +++ b/web/client/plugins/tutorial/preset/cesium_tutorial.js @@ -11,40 +11,35 @@ const I18N = require('../../../components/I18N/I18N'); const CesiumTooltip = require('../../../components/tutorial/steps/CesiumTooltip'); module.exports = [ - // remove comment to enable intro/autostart - /*{ - translation: 'intro', - selector: '#intro-tutorial' - },*/ - { - translationHTML: 'drawerMenu', - selector: '#drawer-menu-button' - }, { - translation: 'searchBar', - selector: '#map-search-bar' + translation: 'introCesium', + selector: '#intro-tutorial' }, { - translation: 'burgerMenu', - selector: '#mapstore-burger-menu' + title: , + text: , + selector: '#map .cesium-viewer', + position: 'bottom' }, { translation: 'cesiumCompass', selector: '#distanceLegendDiv .compass' }, { - translation: 'cesiumNavigation', - selector: '#distanceLegendDiv .navigation-controls' + translationHTML: 'drawerMenu', + selector: '#drawer-menu-button' }, { - translation: 'zoomInButton', - selector: '#zoomin-btn', - position: 'top' + translation: 'searchBar', + selector: '#map-search-bar' }, { - translation: 'zoomOutButton', - selector: '#zoomout-btn', - position: 'top' + translation: 'home', + selector: '#home-button' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' }, { translation: 'fullscreen', @@ -55,15 +50,5 @@ module.exports = [ translation: 'identifyButton', selector: '#identifyBar-container', position: 'top' - }, - { - title: , - text: , - selector: '#map .cesium-viewer', - position: 'bottom' - }, - { - translation: 'home', - selector: '#home-button' } ]; diff --git a/web/client/plugins/tutorial/preset/default_mobile_tutorial.js b/web/client/plugins/tutorial/preset/default_mobile_tutorial.js new file mode 100644 index 0000000000..cb68be2dd8 --- /dev/null +++ b/web/client/plugins/tutorial/preset/default_mobile_tutorial.js @@ -0,0 +1,26 @@ +/** + * 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. + */ + +module.exports = [ + { + translation: 'drawerMenu', + selector: '#drawer-menu-button' + }, + { + translation: 'home', + selector: '#home-button' + }, + { + translation: 'searchButton', + selector: '#search-help' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' + } +]; diff --git a/web/client/plugins/tutorial/preset/default_tutorial.js b/web/client/plugins/tutorial/preset/default_tutorial.js new file mode 100644 index 0000000000..0baea9b50b --- /dev/null +++ b/web/client/plugins/tutorial/preset/default_tutorial.js @@ -0,0 +1,46 @@ +/** + * 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. + */ + +module.exports = [ + { + translationHTML: 'drawerMenu', + selector: '#drawer-menu-button' + }, + { + translation: 'searchBar', + selector: '#map-search-bar' + }, + { + translation: 'home', + selector: '#home-button' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' + }, + { + translation: 'zoomInButton', + selector: '#zoomin-btn', + position: 'top' + }, + { + translation: 'zoomOutButton', + selector: '#zoomout-btn', + position: 'top' + }, + { + translation: 'fullscreen', + selector: '#fullscreen-btn', + position: 'top' + }, + { + translation: 'identifyButton', + selector: '#identifyBar-container', + position: 'top' + } +]; diff --git a/web/client/plugins/tutorial/preset/home.js b/web/client/plugins/tutorial/preset/home_tutorial.js similarity index 72% rename from web/client/plugins/tutorial/preset/home.js rename to web/client/plugins/tutorial/preset/home_tutorial.js index 76a206102e..bf9abc21f5 100644 --- a/web/client/plugins/tutorial/preset/home.js +++ b/web/client/plugins/tutorial/preset/home_tutorial.js @@ -7,12 +7,6 @@ */ module.exports = [ - // add Tutorial plugin to homepage, "maps" in localConfig with cfg: {preset: "home"} - // remove comment to enable intro/autostart - /*{ - translation: 'intro', - selector: '#intro-tutorial' - },*/ { translation: 'mapType', selector: '#mapstore-maptype', diff --git a/web/client/reducers/tutorial.js b/web/client/reducers/tutorial.js index a86cb77875..fe2eafd03d 100644 --- a/web/client/reducers/tutorial.js +++ b/web/client/reducers/tutorial.js @@ -28,7 +28,8 @@ const initialState = { disabled: false, status: 'close', stepIndex: 0, - tourAction: 'next' + tourAction: 'next', + id: '' }; function tutorial(state = initialState, action) { @@ -42,6 +43,12 @@ function tutorial(state = initialState, action) { case SETUP_TUTORIAL: let setup = {}; setup.steps = [].concat(action.steps); + setup.id = action.id; + setup.checkbox = action.checkbox ? action.checkbox : assign({}, state.checkbox); + setup.style = action.style ? action.style : assign({}, state.style); + setup.defaultStep = action.defaultStep ? action.defaultStep : assign({}, state.defaultStep); + setup.disabled = false; + setup.steps = setup.steps.filter((step) => { return step.selector && step.selector.substring(0, 1) === '#' || step.selector.substring(0, 1) === '.'; }).map((step, index) => { @@ -51,11 +58,11 @@ function tutorial(state = initialState, action) { let text = step.text ? step.text : ''; text = step.translation ? : text; text = step.translationHTML ? : text; - text = (step.selector === '#intro-tutorial') ?
{text}
{action.checkbox}
: text; - let style = (step.selector === '#intro-tutorial') ? action.style : {}; + text = (step.selector === '#intro-tutorial') ?
{text}
{setup.checkbox}
: text; + let style = (step.selector === '#intro-tutorial') ? setup.style : {}; let isFixed = (step.selector === '#intro-tutorial') ? true : step.isFixed || false; assign(style, step.style); - return assign({}, action.defaultStep, step, { + return assign({}, setup.defaultStep, step, { index, title, text, @@ -64,7 +71,7 @@ function tutorial(state = initialState, action) { }); }); - const isDisabled = localStorage.getItem('mapstore.plugin.tutorial.disabled'); + const isDisabled = localStorage.getItem('mapstore.plugin.tutorial.' + action.id + '.disabled'); let hasIntro = false; setup.steps.forEach((step) => { if (step.selector === '#intro-tutorial') { @@ -80,7 +87,7 @@ function tutorial(state = initialState, action) { setup.steps = setup.steps.filter((step) => { return step.selector !== '#intro-tutorial'; }).map((step, index) => { - return assign(step, {index}); + return assign({}, step, {index}); }); setup.run = false; @@ -106,7 +113,7 @@ function tutorial(state = initialState, action) { update.steps = update.steps.filter((step) => { return step.selector !== '#intro-tutorial'; }).map((step, index) => { - return assign(step, {index}); + return assign({}, step, {index}); }); } else if (action.tour.type === 'error:target_not_found') { update.status = 'error'; @@ -118,7 +125,7 @@ function tutorial(state = initialState, action) { return assign({}, state, update); case DISABLE_TUTORIAL: let disabled = !state.disabled; - localStorage.setItem('mapstore.plugin.tutorial.disabled', disabled); + localStorage.setItem('mapstore.plugin.tutorial.' + state.id + '.disabled', disabled); return assign({}, state, { disabled }); diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE index b5efc2e420..c7f00a9080 100644 --- a/web/client/translations/data.de-DE +++ b/web/client/translations/data.de-DE @@ -900,6 +900,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US index ed0118882e..533215891d 100644 --- a/web/client/translations/data.en-US +++ b/web/client/translations/data.en-US @@ -900,6 +900,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR index 71822066c5..64fe2ddad9 100644 --- a/web/client/translations/data.fr-FR +++ b/web/client/translations/data.fr-FR @@ -902,6 +902,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT index e58be86a76..04962a21b0 100644 --- a/web/client/translations/data.it-IT +++ b/web/client/translations/data.it-IT @@ -900,6 +900,10 @@ "title": "Applicazioni personalizzate", "text": "Puoi utilizzare componenti e plugins di MapStore2 per costruire applicazioni personalizzate" }, + "introCesium": { + "title": "Istruzioni della mappa 3D", + "text": "Premi il pulsante avanti per aprire il tutorial" + }, "cesium": { "title": "Interazioni con la mappa", "pan": "Vista Pan",