From 4faef390dd7270f64efaa60850dc4814806b6b10 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Wed, 28 Nov 2018 10:14:26 -0500 Subject: [PATCH] Handle visibility between layers sharing a webgl renderer. --- src/layer.js | 7 +++++-- src/main.styl | 6 +++++- src/webgl/layer.js | 24 +++++++++++++++++++++++- src/webgl/object.js | 18 +++++++++++++++++- src/webgl/quadFeature.js | 4 ++-- src/webgl/tileLayer.js | 36 ++++++++++++++++++++++++++++++++++++ tests/cases/osmLayer.js | 21 +++++++++++++++++++++ 7 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/layer.js b/src/layer.js index f1718f0f4d..c003556d88 100644 --- a/src/layer.js +++ b/src/layer.js @@ -254,7 +254,7 @@ var layer = function (arg) { * receive native mouse events. * * @param {boolean} [arg] If specified, the new `active` value. - * @returns {boolean|object} + * @returns {boolean|this} */ this.active = function (arg) { if (arg === undefined) { @@ -457,7 +457,7 @@ var layer = function (arg) { } if (m_visible !== val) { m_visible = val; - m_node.css('display', m_visible ? '' : 'none'); + m_node.toggleClass('hidden', !m_visible); m_this.modified(); } return m_this; @@ -584,6 +584,8 @@ var layer = function (arg) { /** * Get or set the current layer opacity. The opacity is in the range [0-1]. + * An opacity of 0 is not the same as setting `visible(false)`, as + * interactions can still occurr with the layer. * * @param {number} [opacity] If specified, set the opacity. Otherwise, * return the opacity. @@ -601,6 +603,7 @@ var layer = function (arg) { // Create top level div for the layer m_node = $(document.createElement('div')); m_node.addClass('geojs-layer'); + m_node.attr('renderer', m_rendererName); if (m_name) { m_node.attr('id', m_name); } diff --git a/src/main.styl b/src/main.styl index c4c14b0712..ea12f19d0c 100644 --- a/src/main.styl +++ b/src/main.styl @@ -33,9 +33,13 @@ left 0 top 0 pointer-events none - &.active + &.active:not(.hidden) > * pointer-events auto + &.hidden + display none + &.hidden[renderer="webgl"] + display inherit .geo-tile-layer transform-origin 0px 0px diff --git a/src/webgl/layer.js b/src/webgl/layer.js index baca8fc0fd..569937a0e4 100644 --- a/src/webgl/layer.js +++ b/src/webgl/layer.js @@ -4,8 +4,30 @@ var webgl_layer = function () { 'use strict'; var m_this = this, + s_visible = this.visible, s_zIndex = this.zIndex; + /** + * Get/Set visibility of the layer. + * + * @param {boolean} [val] If specified, change the visibility. Otherwise, + * get it. + * @returns {boolean|this} either the visibility (if getting) or the layer + * (if setting). + */ + this.visible = function (val) { + if (val === undefined) { + return s_visible(); + } + var origVal = s_visible(), + result = s_visible.apply(m_this, arguments); + if (origVal !== val && m_this.initialized()) { + m_this.map().scheduleAnimationFrame(m_this._update, true); + m_this.renderer()._render(); + } + return result; + }; + /** * Get or set the z-index of the layer. The z-index controls the display * order of the layers in much the same way as the CSS z-index property. @@ -19,7 +41,7 @@ var webgl_layer = function () { */ this.zIndex = function (zIndex, allowDuplicate) { var result = s_zIndex.apply(m_this, arguments); - if (zIndex !== undefined) { + if (zIndex !== undefined && m_this.initialized()) { /* If the z-index has changed, schedule rerendering the layer. */ m_this.map().scheduleAnimationFrame(m_this._update, true); m_this.renderer()._render(); diff --git a/src/webgl/object.js b/src/webgl/object.js index 9650e87ceb..c57cc5c9f1 100644 --- a/src/webgl/object.js +++ b/src/webgl/object.js @@ -38,8 +38,24 @@ var webgl_object = function (arg) { if (this.bin) { var s_bin = this.bin; + /** + * Get/Set bin of the feature. The bin number is used to determine the + * order of multiple features on the same layer. It has no effect except + * on the webgl renderer. A negative value hides the feature without + * stopping interaction with it. Otherwise, features with higher bin + * numbers are drawn above those with lower bin numbers. If two features + * have the same bin number, their order relative to one another is + * indeterminate and may be unstable. + * + * @param {number} [val] The new bin number. If `undefined`, return the + * current bin number. If `null`, the bin is dynamically computed based + * on order within the parent. If children are nested, this may not be + * what is desired. + * @param {boolean} [actualValue] If truthy and `val` is undefined, return + * the actual value of bin, rather than the dynamically computed value. + * @returns {number|this} The current bin number or a reference to `this`. + */ this.bin = function (val, actualValue) { - if (val === undefined && !actualValue && s_bin(undefined, true) === null) { var layer = m_this.layer && m_this.layer(), map = layer && layer.map && layer.map(), diff --git a/src/webgl/quadFeature.js b/src/webgl/quadFeature.js index d846b84cde..f52afbdce6 100644 --- a/src/webgl/quadFeature.js +++ b/src/webgl/quadFeature.js @@ -411,11 +411,11 @@ var webgl_quadFeature = function (arg) { m_this._build(); } if (m_actor_color) { - m_actor_color.setVisible(m_this.visible(undefined, true)); + m_actor_color.setVisible(m_this.visible()); m_actor_color.material().setBinNumber(m_this.bin()); } if (m_actor_image) { - m_actor_image.setVisible(m_this.visible(undefined, true)); + m_actor_image.setVisible(m_this.visible()); m_actor_image.material().setBinNumber(m_this.bin()); } m_this.updateTime().modified(); diff --git a/src/webgl/tileLayer.js b/src/webgl/tileLayer.js index e637522753..24f30ba550 100644 --- a/src/webgl/tileLayer.js +++ b/src/webgl/tileLayer.js @@ -6,6 +6,8 @@ var webgl_tileLayer = function () { var m_this = this, s_init = this._init, s_exit = this._exit, + s_update = this._update, + s_visible = this.visible, s_zIndex = this.zIndex, m_quadFeature, m_nextTileId = 0, @@ -97,6 +99,26 @@ var webgl_tileLayer = function () { } }; + /** + * Get/Set visibility of the layer. + * + * @param {boolean} [val] If specified, change the visibility, otherwise + * return it. + * @returns {boolean|this} The current visibility or the layer. + */ + this.visible = function (val) { + if (val === undefined) { + return s_visible(); + } + if (m_this.visible() !== val) { + s_visible(val); + if (m_quadFeature) { + m_quadFeature.visible(m_quadFeature.visible(undefined, true), true); + } + } + return m_this; + }; + /** * Get or set the z-index of the layer. The z-index controls the display * order of the layers in much the same way as the CSS z-index property. @@ -120,6 +142,20 @@ var webgl_tileLayer = function () { return s_zIndex.apply(m_this, arguments); }; + /** + * Update layer. + * + * @param {object} request A value to pass to the parent class. + * @returns {this} + */ + this._update = function (request) { + s_update.call(m_this, request); + if (m_quadFeature) { + m_quadFeature._update(); + } + return m_this; + }; + /** * Clean up the layer. */ diff --git a/tests/cases/osmLayer.js b/tests/cases/osmLayer.js index b39ce1f6dd..2c4b3a4665 100644 --- a/tests/cases/osmLayer.js +++ b/tests/cases/osmLayer.js @@ -438,6 +438,27 @@ describe('geo.core.osmLayer', function () { vgl.mockCounts().uniform2fv >= (glCounts.uniform2fv || 0) + 9); }); + it('test that tiles aren\'t loaded when not visible', function () { + glCounts = $.extend({}, vgl.mockCounts()); + layer.visible(false); + }); + waitForIt('map to draw after visible false', function () { + return vgl.mockCounts().clear >= glCounts.clear; + }); + it('zoom in', function () { + glCounts = $.extend({}, vgl.mockCounts()); + map.zoom(5); + }); + waitForIt('map to draw after zoom', function () { + return vgl.mockCounts().clear >= glCounts.clear; + }); + it('test that tiles load when visibility returns', function () { + expect(Object.keys(layer.activeTiles).length).toBe(21); + layer.visible(true); + }); + waitForIt('map to draw after visible true', function () { + return Object.keys(layer.activeTiles).length === 25; + }); it('destroy', destroy_map); }); });