diff --git a/src/scene.js b/src/scene.js index 7f97ffc8c..50ee350fd 100755 --- a/src/scene.js +++ b/src/scene.js @@ -748,6 +748,7 @@ export default class Scene { */ loadScene(config_source = null, config_path = null) { this.config_source = config_source || this.config_source; + this.config_globals_applied = []; if (typeof this.config_source === 'string') { this.config_path = Utils.pathForURL(config_path || this.config_source); @@ -979,6 +980,7 @@ export default class Scene { this.generation = ++Scene.generation; this.updating++; + this.config = SceneLoader.applyGlobalProperties(this.config, this.config_globals_applied); this.style_manager.init(); this.view.reset(); this.createLights(); diff --git a/src/scene_loader.js b/src/scene_loader.js index 46a878fa4..84abdd443 100644 --- a/src/scene_loader.js +++ b/src/scene_loader.js @@ -177,26 +177,44 @@ export default SceneLoader = { // Substitutes global scene properties (those defined in the `config.global` object) for any style values // of the form `global.`, for example `color: global.park_color` would be replaced with the value (if any) // defined for the `park_color` property in `config.global.park_color`. - applyGlobalProperties(config) { + applyGlobalProperties(config, applied) { if (!config.global || Object.keys(config.global).length === 0) { return config; // no global properties to transform } + // Parse properties from globals const separator = ':'; const props = flattenProperties(config.global, separator); - function applyProps (obj) { + // Re-apply previously applied properties + // NB: a current shortcoming here is that you cannot "un-link" a target property from a global + // at run-time. Once a global property substitution has been recorderd, it will always be re-applied + // on subsequent scene updates, even if the target property was updated to another literal value. + // This is unlikely to be a common occurrence an acceptable limitation for now. + applied.forEach(({ prop, target, key }) => { + if (target && props[prop]) { + target[key] = props[prop]; + // log('info', `Re-applying ${prop} with value ${props[prop]} to key ${key} in`, target); + } + }); + + // Find and apply new properties + function applyProps (obj, target, key) { // Convert string if (typeof obj === 'string') { - let key = (obj.slice(0, 7) === 'global.') && (obj.slice(7).replace(/\./g, separator)); - if (key && props[key] !== undefined) { - obj = props[key]; + const prop = (obj.slice(0, 7) === 'global.') && (obj.slice(7).replace(/\./g, separator)); + if (prop && props[prop] !== undefined) { + // Save record of where property is applied + applied.push({ prop, target, key }); + + // Apply property + obj = props[prop]; } } // Loop through object properties else if (typeof obj === 'object') { for (let p in obj) { - obj[p] = applyProps(obj[p]); + obj[p] = applyProps(obj[p], obj, p); } } return obj; @@ -218,9 +236,6 @@ export default SceneLoader = { config.styles = config.styles || {}; config.layers = config.layers || {}; - // Replace global scene properties - config = this.applyGlobalProperties(config); - // Assign ids to data sources let source_id = 0; for (let source in config.sources) { @@ -237,19 +252,6 @@ export default SceneLoader = { config.cameras.default = {}; } - // If no camera set as active, use first one - let active = false; - for (let camera of Utils.values(config.cameras)) { - if (camera.active) { - active = true; - break; - } - } - - if (!active) { - config.cameras[Object.keys(config.cameras)[0]].active = true; - } - // If no lights specified, create default if (Object.keys(config.lights).length === 0 || Object.keys(config.lights).every(i => config.lights[i].visible === false)) { diff --git a/src/view.js b/src/view.js index beca28b55..1c770dfd0 100644 --- a/src/view.js +++ b/src/view.js @@ -60,6 +60,10 @@ export default class View { return name; } } + + // If no camera set as active, use first one + let keys = Object.keys(this.scene.config.cameras); + return keys.length && keys[0]; } }