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

Remove the lag between layers. #644

Merged
merged 2 commits into from
Nov 21, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
10 changes: 2 additions & 8 deletions src/d3/d3Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ var d3Renderer = function (arg) {
m_diagonal = null,
m_scale = 1,
m_transform = {dx: 0, dy: 0, rx: 0, ry: 0, rotation: 0},
m_renderAnimFrameRef = null,
m_renderIds = {},
m_removeIds = {},
m_svg = null,
Expand Down Expand Up @@ -509,9 +508,7 @@ var d3Renderer = function (arg) {
m_this._renderFeature(id, parentId);
} else {
m_renderIds[id] = true;
if (m_renderAnimFrameRef === null) {
m_renderAnimFrameRef = window.requestAnimationFrame(m_this._renderFrame);
}
m_this.layer().map().scheduleAnimationFrame(m_this._renderFrame);
}
};

Expand All @@ -524,7 +521,6 @@ var d3Renderer = function (arg) {
m_removeIds = {};
var ids = m_renderIds;
m_renderIds = {};
m_renderAnimFrameRef = null;
for (id in ids) {
if (ids.hasOwnProperty(id)) {
m_this._renderFeature(id);
Expand Down Expand Up @@ -578,9 +574,7 @@ var d3Renderer = function (arg) {
////////////////////////////////////////////////////////////////////////////
this._removeFeature = function (id) {
m_removeIds[id] = true;
if (m_renderAnimFrameRef === null) {
m_renderAnimFrameRef = window.requestAnimationFrame(m_this._renderFrame);
}
m_this.layer().map().scheduleAnimationFrame(m_this._renderFrame);
delete m_features[id];
if (m_renderIds[id]) {
delete m_renderIds[id];
Expand Down
4 changes: 2 additions & 2 deletions src/gl/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,11 @@ var gl_polygonFeature = function (arg) {
////////////////////////////////////////////////////////////////////////////
this._update = function (opts) {
if (opts && opts.mayDelay) {
m_updateAnimFrameRef = window.requestAnimationFrame(this._update);
m_updateAnimFrameRef = m_this.layer().map().scheduleAnimationFrame(m_this._update);
return;
}
if (m_updateAnimFrameRef) {
window.cancelAnimationFrame(m_updateAnimFrameRef);
m_this.layer().map().scheduleAnimationFrame(m_this._update, 'remove');
m_updateAnimFrameRef = null;
}
s_update.call(m_this);
Expand Down
3 changes: 1 addition & 2 deletions src/gl/quadFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ var gl_quadFeature = function (arg) {
if (m_clrModelViewUniform) {
m_clrModelViewUniform.setOrigin(m_quads.origin);
}
m_this._updateTextures();
m_this.buildTime().modified();
};

Expand Down Expand Up @@ -330,8 +331,6 @@ var gl_quadFeature = function (arg) {
opacity = 1,
crop = {x: 1, y: 1}, quadcrop;

m_this._updateTextures();

context.bindBuffer(vgl.GL.ARRAY_BUFFER, m_glBuffers.imgQuadsPosition);
$.each(m_quads.imgQuads, function (idx, quad) {
if (!quad.image) {
Expand Down
25 changes: 16 additions & 9 deletions src/gl/vglRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ var vglRenderer = function (arg) {
m_viewer = null,
m_width = 0,
m_height = 0,
m_renderAnimFrameRef = null,
m_lastZoom,
m_updateCamera = false,
s_init = this._init,
s_exit = this._exit;

Expand Down Expand Up @@ -121,7 +121,7 @@ var vglRenderer = function (arg) {
m_this.canvas().attr('height', h);
renderWindow.positionAndResize(x, y, w, h);

m_this._updateRendererCamera();
m_updateCamera = true;
m_this._render();

return m_this;
Expand All @@ -133,18 +133,24 @@ var vglRenderer = function (arg) {
*/
////////////////////////////////////////////////////////////////////////////
this._render = function () {
if (m_renderAnimFrameRef) {
window.cancelAnimationFrame(m_renderAnimFrameRef);
}
m_renderAnimFrameRef = window.requestAnimationFrame(this._renderFrame);
/* If we are already scheduled to render, don't schedule again. Rather,
* mark that we should render after other animation frame requests occur.
* It would be nice if we could just reschedule the call by removing and
* readding the animation frame request, but this doesn't work for if the
* reschedule occurs during another animation frame callback (it then waits
* until a subsequent frame). */
m_this.layer().map().scheduleAnimationFrame(this._renderFrame, true);
return m_this;
};

/**
* This clears the render timer and actually renders.
*/
this._renderFrame = function () {
m_renderAnimFrameRef = null;
if (m_updateCamera) {
m_updateCamera = false;
m_this._updateRendererCamera();
}
m_viewer.render();
};

Expand Down Expand Up @@ -217,7 +223,7 @@ var vglRenderer = function (arg) {
// produce a pan
m_this.layer().geoOn(geo_event.pan, function (evt) {
void (evt);
m_this._updateRendererCamera();
m_updateCamera = true;
});

// Connect to parallelprojection event
Expand All @@ -230,10 +236,11 @@ var vglRenderer = function (arg) {
if (!vglRenderer || !vglRenderer.camera()) {
console.log('Parallel projection event triggered on unconnected VGL ' +
'renderer.');
return;
}
camera = vglRenderer.camera();
camera.setEnableParallelProjection(evt.parallelProjection);
m_this._updateRendererCamera();
m_updateCamera = true;
}
});

Expand Down
58 changes: 56 additions & 2 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ var sceneObject = require('./sceneObject');
* @param {geo.camera?} camera The camera to control the view
* @param {geo.mapInteractor?} interactor The UI event handler
* @param {geo.clock?} clock The clock used to synchronize time events
* @param {array} [animationQueue] An array used to synchonize animations. If
* specified, this should be an empty array or the same array as passed to
* other map instances.
* @param {boolean} [autoResize=true] Adjust map size on window resize
* @param {boolean} [clampBoundsX=false] Prevent panning outside of the
* maximum bounds in the horizontal direction.
Expand Down Expand Up @@ -127,6 +130,7 @@ var map = function (arg) {
m_clampBoundsX,
m_clampBoundsY,
m_clampZoom,
m_animationQueue = arg.animationQueue || [],
m_origin,
m_scale = {x: 1, y: 1, z: 1}; // constant and ignored for the moment

Expand Down Expand Up @@ -1223,7 +1227,7 @@ var map = function (arg) {
}
m_this.rotation(p[3], undefined, true);

window.requestAnimationFrame(anim);
m_this.scheduleAnimationFrame(anim);
}

m_this.geoTrigger(geo_event.transitionstart, opts);
Expand All @@ -1239,7 +1243,7 @@ var map = function (arg) {
} else if (animTime) {
anim(animTime);
} else {
window.requestAnimationFrame(anim);
m_this.scheduleAnimationFrame(anim);
}
return m_this;
};
Expand Down Expand Up @@ -1560,6 +1564,56 @@ var map = function (arg) {
return m_this;
};

/**
* Instead of each function using window.requestAnimationFrame, schedule all
* such frames here. This allows the callbacks to be reordered or removed as
* needed and reduces overhead in Chrome a small amount. Also, if the
* animation queue is shared between map instances, the callbacks will be
* called as one, providing better synchronization.
*
* @param {function} callback: function to call during the animation frame.
* It is called with an animation epoch, exactly as requestAnimationFrame.
* @param {string|boolean} action: falsy to only add the callback if it is
* not already scheduled. 'remove' to remove the callback (use this
* instead of cancelAnimationFrame). Any other truthy value moves the
* callback to the end of the list.
* @returns {integer} An integer as returned by window.requestAnimationFrame.
*/
this.scheduleAnimationFrame = function (callback, action) {
if (!m_animationQueue.length) {
/* By refering to requestAnimationFrame as a property of window, versus
* explicitly using window.requestAnimationFrame, we prevent the
* stripping of 'window' off of the reference and allow our tests to
* override this if needed. */
m_animationQueue.push(window['requestAnimationFrame'](processAnimationFrame));
}
var pos = m_animationQueue.indexOf(callback, 1);
if (pos >= 0) {
if (!action) {
return;
}
m_animationQueue.splice(pos, 1);
if (action === 'remove') {
return;
}
}
m_animationQueue.push(callback);
return m_animationQueue[0];
};

/**
* Sevice the callback during an animation frame. This uses splice to modify
* the animationQueue to allow multiple map instances to share the queue.
*/
function processAnimationFrame() {
var queue = m_animationQueue.splice(0, m_animationQueue.length);

/* The first entry is the reference to the window.requestAnimationFrame. */
for (var i = 1; i < queue.length; i += 1) {
queue[i].apply(this, arguments);
}
}

////////////////////////////////////////////////////////////////////////////
//
// The following are some private methods for interacting with the camera.
Expand Down
4 changes: 2 additions & 2 deletions src/mapInteractor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1431,11 +1431,11 @@ var mapInteractor = function (args) {
}

if (m_state.handler) {
window.requestAnimationFrame(m_state.handler);
m_this.map().scheduleAnimationFrame(m_state.handler);
}
};
if (m_state.handler) {
window.requestAnimationFrame(m_state.handler);
m_this.map().scheduleAnimationFrame(m_state.handler);
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/util/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@
} else if (!stop && !m_originalRequestAnimationFrame) {
m_originalRequestAnimationFrame = window.requestAnimationFrame;
window.requestAnimationFrame = function (callback) {
m_originalRequestAnimationFrame.call(window, function (timestamp) {
return m_originalRequestAnimationFrame.call(window, function (timestamp) {
var track = m_timingData.requestAnimationFrame, recent;
/* Some environments have unsynchronized performance and time
* counters. The nowDelta factor compensates for this. For
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/d3GraphFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ describe('d3 graph feature', function () {
var map, layer, feature;

it('Setup map', function () {
mockAnimationFrame();
map = geo.map({node: '#map-d3-graph-feature', center: [0, 0], zoom: 3});
layer = map.createLayer('feature', {'renderer': 'd3'});
});

it('Add features to a layer', function () {
mockAnimationFrame();
var selection, nodes;

nodes = [
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/d3PointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ describe('d3 point feature', function () {
var map, width = 800, height = 600, layer, feature1, feature2;

it('Setup map', function () {
mockAnimationFrame();
map = geo.map({node: '#map-d3-point-feature', center: [0, 0], zoom: 3});
layer = map.createLayer('feature', {'renderer': 'd3'});

map.resize(0, 0, width, height);
});

it('Add features to a layer', function () {
mockAnimationFrame();
var selection;
feature1 = layer.createFeature('point', {selectionAPI: true})
.data([{y: 0, x: 0}, {y: 10, x: 0}, {y: 0, x: 10}])
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/d3VectorFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('d3 vector feature', function () {
var map, layer, feature1;

it('Create a map with a d3 feature layer', function () {
mockAnimationFrame();
d3.select('body').append('div').attr('id', 'map-d3-vector');
map = geo.map({node: '#map-d3-vector',
center: [0, 0],
Expand All @@ -36,7 +37,6 @@ describe('d3 vector feature', function () {
});

it('Add features to a layer', function () {
mockAnimationFrame();
var vectorLines, featureGroup, markers;
feature1 = layer.createFeature('vector')
.data([{y: 0, x: 0}, {y: 10, x: 0}, {y: 0, x: 10}])
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ describe('geo.core.map', function () {
expect(closeToEqual(zc.center, {x: 0, y: 0})).toBe(true);
});
it('transition', function () {
var m = create_map(), start, wasCalled;
mockAnimationFrame();
var m = create_map(), start, wasCalled;
expect(m.transition()).toBe(null);
start = new Date().getTime();
m.transition({
Expand Down
7 changes: 5 additions & 2 deletions tests/cases/mapInteractor.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ describe('mapInteractor', function () {
map.gcs = function (arg) {
return 'EPSG:3857';
};
map.scheduleAnimationFrame = function (callback) {
return window['requestAnimationFrame'](callback);
};
return map;
}

Expand Down Expand Up @@ -1327,6 +1330,7 @@ describe('mapInteractor', function () {
});

it('Test momentum', function () {
mockAnimationFrame();
var map = mockedMap('#mapNode1'), start;

var interactor = geo.mapInteractor({
Expand All @@ -1338,7 +1342,6 @@ describe('mapInteractor', function () {
}],
throttle: false
});
mockAnimationFrame();
mockDate();
// initiate a pan and release
interactor.simulateEvent(
Expand Down Expand Up @@ -1380,6 +1383,7 @@ describe('mapInteractor', function () {
});

it('Test springback', function () {
mockAnimationFrame();
$('#mapNode1').css({width: '400px', height: '400px'});
var map = mockedMap('#mapNode1'), start;

Expand All @@ -1393,7 +1397,6 @@ describe('mapInteractor', function () {
}],
throttle: false
});
mockAnimationFrame();
mockDate();
// pan past the max bounds
interactor.simulateEvent(
Expand Down
1 change: 1 addition & 0 deletions tests/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ module.exports.mockAnimationFrame = function (mockDate) {
animFrameIndex += 1;
var id = animFrameIndex;
animFrameCallbacks.push({id: id, callback: callback});
return id;
}

/* Replace window.cancelAnimationFrame with this function.
Expand Down