-
Notifications
You must be signed in to change notification settings - Fork 75
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
Add a map.screenshot() function. #665
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -899,7 +899,11 @@ var map = function (arg) { | |
throw new Error('Map require DIV node'); | ||
} | ||
|
||
if (m_node.data('data-geojs-map') && $.isFunction(m_node.data('data-geojs-map').exit)) { | ||
m_node.data('data-geojs-map').exit(); | ||
} | ||
m_node.addClass('geojs-map'); | ||
m_node.data('data-geojs-map', m_this); | ||
return m_this; | ||
}; | ||
|
||
|
@@ -923,13 +927,15 @@ var map = function (arg) { | |
//////////////////////////////////////////////////////////////////////////// | ||
this.exit = function () { | ||
var i, layers = m_this.children(); | ||
for (i = 0; i < layers.length; i += 1) { | ||
for (i = layers.length - 1; i >= 0; i -= 1) { | ||
layers[i]._exit(); | ||
m_this.removeChild(layers[i]); | ||
} | ||
if (m_this.interactor()) { | ||
m_this.interactor().destroy(); | ||
m_this.interactor(null); | ||
} | ||
m_this.node().data('data-geojs-map', null); | ||
m_this.node().off('.geo'); | ||
/* make sure the map node has nothing left in it */ | ||
m_this.node().empty(); | ||
|
@@ -1545,6 +1551,69 @@ var map = function (arg) { | |
return m_this; | ||
}; | ||
|
||
/** | ||
* Get a screen-shot of all or some of the canvas layers of map. Note that | ||
* webGL layers are rerendered, even if | ||
* window.contextPreserveDrawingBuffer = true; | ||
* is set before creating the map object. Chrome, at least, may not keep the | ||
* drawing buffers if the tab loses focus (and returning focus won't | ||
* necessarily rerender). | ||
* | ||
* @param {object|array|undefined} layers: either a layer, a list of | ||
* layers, or falsy to get all layers. | ||
* @param {string} type: see canvas.toDataURL. Defaults to 'image/png'. | ||
* Alternately, 'canvas' to return the canvas element (this can be used | ||
* to get the results as a blob, which can be faster for some operations | ||
* but is not supported as widely). | ||
* @param {Number} encoderOptions: see canvas.toDataURL. | ||
* @returns {string|HTMLCanvasElement}: data URL with the result or the | ||
* HTMLCanvasElement with the result. | ||
*/ | ||
this.screenshot = function (layers, type, encoderOptions) { | ||
// ensure layers is a list of all the layres we want to include | ||
if (!layers) { | ||
layers = m_this.layers(); | ||
} else if (!Array.isArray(layers)) { | ||
layers = [layers]; | ||
} | ||
// filter to only the included layers | ||
layers = layers.filter(function (l) { return m_this.layers().indexOf(l) >= 0; }); | ||
// sort layers by z-index | ||
layers = layers.sort( | ||
function (a, b) { return (a.zIndex() - b.zIndex()); } | ||
); | ||
// create a new canvas element | ||
var result = document.createElement('canvas'); | ||
result.width = m_width; | ||
result.height = m_height; | ||
var context = result.getContext('2d'); | ||
// start with a white background | ||
context.fillStyle = 'white'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @manthey do we not need to set the transparency? I believe the later drawImage call will update the final value to the combined value of all opacities. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The drawImage properly uses the opacity of individual pixels in the canvas, so layers composite properly. But... I did forget that we adjust the opacity of the containing div of the layer when you set the layer opacity, so I'll need to take that into account. |
||
context.fillRect(0, 0, result.width, result.height); | ||
// for each layer, copy all canvases to our new canvas. If we ever support | ||
// non-canvases, add them here. It looks like some support could be added | ||
// with a library such as rasterizehtml (avialable on npm). | ||
layers.forEach(function (layer) { | ||
$('canvas', layer.node()).each(function () { | ||
if (layer.renderer().api() === 'vgl') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nice to have it not check for vgl but I understand why we have to do this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I original thought that if we preserved the drawing buffers, this wouldn't be necessary, but they aren't preserved when the browser tab is switched in any case, so this ends up being necessary. |
||
layer.renderer()._renderFrame(); | ||
} | ||
var transform = $(this).css('transform'); | ||
// if the canvas is being transformed, apply the same transformation | ||
if (transform && transform.substr(0, 7) === 'matrix(') { | ||
context.setTransform.apply(context, transform.substr(7, transform.length - 8).split(',').map(parseFloat)); | ||
} else { | ||
context.setTransform(1, 0, 0, 1, 0, 0); | ||
} | ||
context.drawImage($(this)[0], 0, 0); | ||
}); | ||
}); | ||
if (type !== 'canvas') { | ||
result = result.toDataURL(type, encoderOptions); | ||
} | ||
return result; | ||
}; | ||
|
||
/** | ||
* Instead of each function using window.requestAnimationFrame, schedule all | ||
* such frames here. This allows the callbacks to be reordered or removed as | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the API