Skip to content

Commit

Permalink
Support mix-blend-mode compositing in screenshots.
Browse files Browse the repository at this point in the history
There are limitations to the current screenshot function.  If layers are
composited with mix-blend-mode, svg filters, or some other options,
these are not applied.  mix-blend-mode support is added here; other
limitations remain.
  • Loading branch information
manthey committed Mar 2, 2021
1 parent 77c4021 commit 9bbf038
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sudo: required
dist: xenial

node_js:
- 14
- 12

addons:
# version 55.0 - 57.x have an issue with screenshots.
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## Unreleased

### Improvements
- Screenshots now handle mix-blend-mode settings on top level divs (#1074)

### Bug Fixes
- Fixed an issue with affine transforms and polygons (#1073)

## Version 0.20.0

### Features
Expand Down
13 changes: 9 additions & 4 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -1820,13 +1820,13 @@ var map = function (arg) {
if (layer.renderer() && layer.renderer().api() === 'webgl') {
layer.renderer()._renderFrame();
}
drawLayerImageToContext(context, opacity, canvasElem, canvasElem[0]);
drawLayerImageToContext(context, opacity, canvasElem, canvasElem[0], layer.node().css('mix-blend-mode'));
});
});
if ((layer.node().children().not('canvas').length || !layer.node().children().length) && (!layer.renderer() || layer.renderer().api() !== 'webgl')) {
defer = defer.then(function () {
return util.htmlToImage(layer.node(), 1).done(function (img) {
drawLayerImageToContext(context, 1, $([]), img);
drawLayerImageToContext(context, 1, $([]), img, layer.node().css('mix-blend-mode'));
});
});
}
Expand All @@ -1846,7 +1846,7 @@ var map = function (arg) {
var attrElem = $(this);
defer = defer.then(function () {
return util.htmlToImage(attrElem, 1).done(function (img) {
drawLayerImageToContext(context, 1, $([]), img);
drawLayerImageToContext(context, 1, $([]), img, attrElem.css('mix-blend-mode'));
});
});
});
Expand Down Expand Up @@ -1963,10 +1963,14 @@ var map = function (arg) {
* @param {number} opacity The opacity in the range [0, 1].
* @param {object} elem A jQuery element that might have a transform.
* @param {HTMLImageObject} img The image or canvas to draw to the canvas.
* @param {string} [mixBlendMode] the mix-blend-mode used to add this layer.
* @private
*/
function drawLayerImageToContext(context, opacity, elem, img) {
function drawLayerImageToContext(context, opacity, elem, img, mixBlendMode) {
context.globalAlpha = opacity;
if (mixBlendMode) {
context.globalCompositeOperation = mixBlendMode;
}
var transform = elem.css('transform');
// if the canvas is being transformed, apply the same transformation
if (transform && transform.substr(0, 7) === 'matrix(') {
Expand All @@ -1975,6 +1979,7 @@ var map = function (arg) {
context.setTransform(1, 0, 0, 1, 0, 0);
}
context.drawImage(img, 0, 0);
context.globalCompositeOperation = 'source-over';
}

/**
Expand Down
18 changes: 17 additions & 1 deletion tests/cases/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,6 @@ describe('geo.core.map', function () {
});
});
it('partial opacity', function (done) {
// making a layer transparent is as good as not asking for it
layer2.opacity(0.5);
m.screenshot().then(function (result) {
expect(result).not.toEqual(ss.basic);
Expand All @@ -853,6 +852,23 @@ describe('geo.core.map', function () {
// These tests won't work in PhantomJS. See
// https://bugs.webkit.org/show_bug.cgi?id=17352, also 29305 and 129172.
if (!isPhantomJS()) {
it('mix-blend-mode multiply', function (done) {
layer2.node().css('mix-blend-mode', 'multiply');
m.screenshot().then(function (result) {
expect(result).not.toEqual(ss.basic);
expect(result).not.toEqual(ss.onelayer);
layer2.node().css('mix-blend-mode', 'initial');
done();
});
});
it('mix-blend-mode normal', function (done) {
layer2.node().css('mix-blend-mode', 'normal');
m.screenshot().then(function (result) {
expect(result).toEqual(ss.basic);
layer2.node().css('mix-blend-mode', 'initial');
done();
});
});
it('layer background', function (done) {
var layer3 = m.createLayer('ui');
layer3.node().css('background-image', 'url(/data/tilefancy.png)');
Expand Down

0 comments on commit 9bbf038

Please sign in to comment.