Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clear quads on layer addition and removal. #1010

Merged
merged 3 commits into from
Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ var rendererForAnnotations = require('./registry').rendererForAnnotations;
* to determine the renderer. If a {@link geo.renderer} instance, the
* renderer is not recreated; not all renderers can be shared by multiple
* layers.
* @property {boolean} [autoshareRenderer=true] If truthy and the renderer
* supports it, auto-share renderers between layers. Currently, auto-sharing
* can only occur for webgl renderers, and will only occur between adjacent
* layers than have the same opacity. Shared renderers has slightly
* different behavior than non-shared renderers: changing z-index may result
* in rerendering and be slightly slower; only one DOM canvas is used for all
* shared renderers. Some features have slight z-stacking differences in
* shared versus non-shared renderers.
* @property {boolean|string} [autoshareRenderer=true] If truthy and the
* renderer supports it, auto-share renderers between layers. Currently,
* auto-sharing can only occur for webgl renderers and adjacent layers. If
* `true`, sharing will only occur if the layers have the same opacity and it
* is 1 or 0 and any tile layers are below non-tile layers. If `"more"`,
* sharing will occur for any adjacent layers that have the same opacity.
* Shared renderers has slightly different behavior than non-shared
* renderers: changing z-index may result in rerendering and be slightly
* slower; only one DOM canvas is used for all shared renderers. Some
* features have slight z-stacking differences in shared versus non-shared
* renderers.
* @property {HTMLElement} [canvas] If specified, use this canvas rather than
* a canvas associaied with the renderer directly. Renderers may not support
* sharing a canvas.
Expand Down Expand Up @@ -137,7 +140,7 @@ var layer = function (arg) {
/**
* Get the setting of autoshareRenderer.
*
* @returns {boolean}
* @returns {boolean|string}
*/
this.autoshareRenderer = function () {
return m_autoshareRenderer;
Expand Down
23 changes: 23 additions & 0 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ var sceneObject = require('./sceneObject');
* maximum bounds in the vertical direction.
* @property {boolean} [clampZoom=true] Prevent zooming out so that the map
* area is smaller than the window.
* @property {boolean|string} [autoshareRenderer] If specified, pass this value
* to layers when they are created. See
* {@link geo.layer.spec#autoshareRenderer} for valid values.
*/

/**
Expand Down Expand Up @@ -133,6 +136,7 @@ var map = function (arg) {
m_clampZoom,
m_animationQueue = arg.animationQueue || [],
m_autoResize = arg.autoResize === undefined ? true : arg.autoResize,
m_autoshareRenderer = arg.autoshareRenderer,
m_origin;

/* Compute the maximum bounds on our map projection. By default, x ranges
Expand Down Expand Up @@ -614,6 +618,9 @@ var map = function (arg) {
*/
this.createLayer = function (layerName, arg) {
arg = arg || {};
if (m_this.autoshareRenderer() !== undefined) {
arg = Object.assign({autoshareRenderer: m_this.autoshareRenderer()}, arg);
}
var newLayer = registry.createLayer(
layerName, m_this, arg);

Expand Down Expand Up @@ -1873,6 +1880,22 @@ var map = function (arg) {
return zoom;
};

/**
* Get or set the setting of autoshareRenderer.
*
* @param {boolean|string|null} [arg] If specified, the new value for
* autoshareRender that gets passed to created layers. `null` will clear
* the value.
* @returns {boolean|string|this}
*/
this.autoshareRenderer = function (arg) {
if (arg === undefined) {
return m_autoshareRenderer;
}
m_autoshareRenderer = arg === null ? undefined : arg;
return m_this;
};

/**
* Draw a layer image to a canvas context. The layer's opacity and transform
* are applied. This is used as part of making a screenshot.
Expand Down
12 changes: 9 additions & 3 deletions src/webgl/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var webgl_layer = function () {
var createRenderer = require('../registry').createRenderer;
var geo_event = require('../event');
var webglRenderer = require('./webglRenderer');
var tileLayer = require('../tileLayer');

var m_this = this,
s_init = this._init,
Expand Down Expand Up @@ -137,23 +138,28 @@ var webgl_layer = function () {
var layers = map.sortedLayers(),
renderer,
rerender_list = [],
opacity;
opacity,
lowerTileLayers;
layers.forEach(function (layer) {
if (!layer.autoshareRenderer() || !layer.renderer() || layer.renderer().api() !== webglRenderer.apiname) {
let autoshare = layer.autoshareRenderer(),
isTileLayer = layer instanceof tileLayer;
if (!autoshare || !layer.renderer() || layer.renderer().api() !== webglRenderer.apiname) {
renderer = null;
} else if (!renderer || layer.opacity() !== opacity) {
} else if (!renderer || layer.opacity() !== opacity || (autoshare !== 'more' && ((layer.opacity() > 0 && layer.opacity() < 1) || (isTileLayer && !lowerTileLayers)))) {
if (!layer.node()[0].contains(layer.renderer().canvas()[0])) {
layer.switchRenderer(createRenderer(webglRenderer.apiname, layer), false);
rerender_list.push(layer.renderer());
}
renderer = layer.renderer();
opacity = layer.opacity();
lowerTileLayers = isTileLayer;
} else {
if (layer.renderer() !== renderer) {
rerender_list.push(layer.renderer());
layer.switchRenderer(renderer, false);
rerender_list.push(layer.renderer());
}
lowerTileLayers &= isTileLayer;
}
});
layers.forEach(function (layer) {
Expand Down
31 changes: 25 additions & 6 deletions src/webgl/tileLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ var tileLayer = require('../tileLayer');

var webgl_tileLayer = function () {
'use strict';

var geo_event = require('../event');

var m_this = this,
s_init = this._init,
s_exit = this._exit,
Expand Down Expand Up @@ -132,16 +135,28 @@ var webgl_tileLayer = function () {
*/
this.zIndex = function (zIndex, allowDuplicate) {
if (zIndex !== undefined) {
/* If the z-index has changed, clear the quads so they are composited in
* the correct order. */
m_this.clear();
if (m_quadFeature) {
m_quadFeature.modified();
}
this._clearQuads(true);
}
return s_zIndex.apply(m_this, arguments);
};

/**
* If the z-index has changed or layers are added or removed, clear the quads
* so they are composited in the correct order.
*
* @param {boolean} [noredraw] If truthy, don't redraw after clearing the
* quads.
*/
this._clearQuads = function (noredraw) {
m_this.clear();
if (m_quadFeature) {
m_quadFeature.modified();
}
if (noredraw !== true) {
this.draw();
}
};

/**
* Update layer.
*
Expand Down Expand Up @@ -197,6 +212,10 @@ var webgl_tileLayer = function () {
m_quadFeature.gcs(m_this._options.gcs || m_this.map().gcs());
m_quadFeature.data(m_tiles);
m_quadFeature._update();

var map = m_this.map();
map.geoOn(geo_event.layerAdd, this._clearQuads);
map.geoOn(geo_event.layerRemove, this._clearQuads);
};

/* These functions don't need to do anything. */
Expand Down
68 changes: 65 additions & 3 deletions tests/cases/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ describe('geo.webgl.layer', function () {
restoreWebglRenderer();
});
});
describe('autoshareRenderer is true', function () {
describe('autoshareRenderer is true"', function () {
var map, layer1, layer2, layer3;
it('_init', function (done) {
mockWebglRenderer();
Expand All @@ -348,6 +348,68 @@ describe('geo.webgl.layer', function () {
layer2.visible(true);
expect($('canvas', map.node()).length).toBe(1);
});
it('opacity', function () {
layer1.opacity(0.5);
expect($('canvas', map.node()).length).toBe(2);
layer2.opacity(0.5);
expect($('canvas', map.node()).length).toBe(3);
layer1.opacity(1);
expect($('canvas', map.node()).length).toBe(3);
layer2.opacity(1);
expect($('canvas', map.node()).length).toBe(1);
});
it('zIndex', function () {
expect($('canvas', layer1.node()).length).toBe(1);
expect($('canvas', layer2.node()).length).toBe(0);
expect($('canvas', layer3.node()).length).toBe(0);
layer1.moveUp();
expect($('canvas', map.node()).length).toBe(1);
expect($('canvas', layer1.node()).length).toBe(0);
expect($('canvas', layer2.node()).length).toBe(1);
expect($('canvas', layer3.node()).length).toBe(0);
layer1.moveUp();
expect($('canvas', map.node()).length).toBe(2);
expect($('canvas', layer1.node()).length).toBe(1);
expect($('canvas', layer2.node()).length).toBe(1);
expect($('canvas', layer3.node()).length).toBe(0);
layer1.moveToBottom();
expect($('canvas', map.node()).length).toBe(1);
expect($('canvas', layer1.node()).length).toBe(1);
expect($('canvas', layer2.node()).length).toBe(0);
expect($('canvas', layer3.node()).length).toBe(0);
});
it('cleanup', function () {
console.log.restore();
destroyMap();
restoreWebglRenderer();
});
});
describe('autoshareRenderer is "more"', function () {
var map, layer1, layer2, layer3;
it('_init', function (done) {
mockWebglRenderer();
sinon.stub(console, 'log', function () {});
map = createMap();
map.autoshareRenderer('more');
layer1 = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/white.jpg'});
layer2 = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/weather.png', keepLower: false});
layer3 = map.createLayer('feature', {renderer: 'webgl'});
layer3.createFeature('point', {}).data([{x: 2, y: 1}]);
map.onIdle(function () {
expect($('canvas', map.node()).length).toBe(1);
done();
});
});
it('visible', function () {
layer1.visible(false);
expect($('canvas', map.node()).length).toBe(1);
layer1.visible(true);
expect($('canvas', map.node()).length).toBe(1);
layer2.visible(false);
expect($('canvas', map.node()).length).toBe(1);
layer2.visible(true);
expect($('canvas', map.node()).length).toBe(1);
});
it('opacity', function () {
layer1.opacity(0.5);
expect($('canvas', map.node()).length).toBe(2);
Expand Down Expand Up @@ -390,9 +452,9 @@ describe('geo.webgl.layer', function () {
mockWebglRenderer();
sinon.stub(console, 'log', function () {});
map = createMap();
layer1 = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/white.jpg'});
layer1 = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/white.jpg', autoshareRenderer: 'more'});
layer2 = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/weather.png', keepLower: false, autoshareRenderer: false});
layer3 = map.createLayer('feature', {renderer: 'webgl'});
layer3 = map.createLayer('feature', {renderer: 'webgl', autoshareRenderer: 'more'});
layer3.createFeature('point', {}).data([{x: 2, y: 1}]);
map.onIdle(function () {
expect($('canvas', map.node()).length).toBe(3);
Expand Down
12 changes: 12 additions & 0 deletions tests/cases/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,18 @@ describe('geo.core.map', function () {
expect(m.fileReader(r)).toBe(m);
expect(m.fileReader()).toBe(r);
});
it('autoshareRenderer', function () {
var m = createMap();
expect(m.autoshareRenderer()).toBe(undefined);
expect(m.autoshareRenderer(false)).toBe(m);
expect(m.autoshareRenderer()).toBe(false);
expect(m.autoshareRenderer(true)).toBe(m);
expect(m.autoshareRenderer()).toBe(true);
expect(m.autoshareRenderer(null)).toBe(m);
expect(m.autoshareRenderer()).toBe(undefined);
m = createMap({autoshareRenderer: 'more'});
expect(m.autoshareRenderer()).toBe('more');
});
});

describe('Public utility methods', function () {
Expand Down