Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

data-canvas

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

data-canvas - npm Package Compare versions

Comparing version 0.0.0 to 0.1.0

data-canvas-stack.gif

2

package.json
{
"name": "data-canvas",
"version": "0.0.0",
"version": "0.1.0",
"description": "Improved event handling and testing for the HTML5 canvas",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -1,2 +0,2 @@

[![Build Status](https://travis-ci.org/hammerlab/data-canvas.svg?branch=travis-tests)](https://travis-ci.org/hammerlab/data-canvas) [![Coverage Status](https://coveralls.io/repos/hammerlab/data-canvas/badge.svg?branch=master&service=github)](https://coveralls.io/github/hammerlab/data-canvas?branch=master)
[![Build Status](https://travis-ci.org/hammerlab/data-canvas.svg?branch=travis-tests)](https://travis-ci.org/hammerlab/data-canvas) [![Coverage Status](https://coveralls.io/repos/hammerlab/data-canvas/badge.svg?branch=master&service=github)](https://coveralls.io/github/hammerlab/data-canvas?branch=master)[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hammerlab/data-canvas?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
data-canvas

@@ -133,2 +133,10 @@ ===========

Here's what the data stack looks like while the rendering happens:
<!--
Code for generating this image is here: http://jsfiddle.net/7nkbfbkb/6/
convert -background white -alpha remove -layers OptimizePlus -delay 75 -dispose Background -loop 0 frame*.png data-canvas-stack.gif
-->
<img src="data-canvas-stack.gif" width=400 height=125>
Testing

@@ -135,0 +143,0 @@ -------

@@ -108,9 +108,130 @@ /**

};
var recordingDrawImage = this.drawImage; // plain recording drawImage()
this.drawImage = function(image) {
// If the drawn image has recorded calls, then they need to be transferred over.
var recorder = RecordingContext.recorderForCanvas(image);
if (!recorder) {
recordingDrawImage.apply(ctx, arguments);
} else {
ctx.drawImage.apply(ctx, arguments);
this.calls = this.calls.concat(transformedCalls(recorder.calls, arguments));
}
}
}
// Transform the calls to a new coordinate system.
// The arguments are those to drawImage().
function transformedCalls(calls, args) {
var image = args[0],
sx = 0,
sy = 0,
sWidth = image.width,
sHeight = image.height,
dx,
dy,
dWidth = image.width,
dHeight = image.height;
if (args.length == 3) {
// void ctx.drawImage(image, dx, dy);
dx = args[1];
dy = args[2];
} else if (args.length == 5) {
// void ctx.drawImage(image, dx, dy, dWidth, dHeight);
dx = args[1];
dy = args[2];
dWidth = args[3];
dHeight = args[4];
} else if (args.length == 9) {
// void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
sx = args[1];
sy = args[2];
sWidth = args[3];
sHeight = args[4];
dx = args[5];
dy = args[6];
dWidth = args[7];
dHeight = args[8];
}
// Other arities will make the browser throw an error on ctx.drawImage.apply
var xScaling = getScaleFactor(sx, sx + sWidth, dx, dx + dWidth),
xScale = makeScale( sx, sx + sWidth, dx, dx + dWidth),
yScaling = getScaleFactor(sy, sy + sHeight, dy, dy + dHeight),
yScale = makeScale( sy, sy + sHeight, dy, dy + dHeight);
// These calls are more complex:
// arc
// arcTo
// ellipse
// TODO: clip calls outside of the source rectangle.
var transformCall = function(originalCall) {
var call = originalCall.slice(), // make a copy
type = call[0];
if (type in CALLS_XY) {
var xys = CALLS_XY[type];
if (typeof(xys) == 'number') xys = [xys];
xys.forEach(function(pos) {
call[1 + pos] = xScale(call[1 + pos]);
call[2 + pos] = yScale(call[2 + pos]);
});
}
if (type in CALLS_WH) {
var whs = CALLS_WH[type];
if (typeof(whs) == 'number') whs = [whs];
whs.forEach(function(pos) {
call[1 + pos] *= xScaling;
call[2 + pos] *= yScaling;
});
}
return call;
};
return calls.map(transformCall);
}
// Helpers for transformedCalls
// Map (x1, x2) --> (y1, y2)
function getScaleFactor(x1, x2, y1, y2) {
return (y2 - y1) / (x2 - x1);
};
function makeScale(x1, x2, y1, y2) {
var scale = getScaleFactor(x1, x2, y1, y2);
return function(x) {
return y1 + scale * (x - x1);
};
};
// These calls all have (x, y) as args at the specified positions.
var CALLS_XY = {
clearRect: 0,
fillRect: 0,
strokeRect: 0,
fillText: 1,
strokeText: 1,
moveTo: 0,
lineTo: 0,
bezierCurveTo: [0, 2, 4],
quadraticCurveTo: [0, 2],
rect: 0
};
// These calls have (width, height) as args at the specified positions.
var CALLS_WH = {
clearRect: 2,
fillRect: 2,
strokeRect: 2,
// fillText has an optional `max_width` param
rect: 2,
};
/**
* Get a list of objects which have been pushed to the data canvas that match
* the particular predicate.
* If no predicate is specified, all objects are returned.
*/
RecordingContext.prototype.drawnObjectsWith = function(predicate) {
if (!predicate) predicate = function() { return true; };
return this.callsOf('pushObject')

@@ -120,2 +241,4 @@ .filter(function(x) { return predicate(x[1]) })

};
// This version reads better if there's no predicate.
RecordingContext.prototype.drawnObjects = RecordingContext.prototype.drawnObjectsWith;

@@ -195,3 +318,5 @@ /**

if (!div) {
if (RecordingContext.recorders.length == 0) {
if (!RecordingContext.recorders) {
throw 'You must call RecordingContext.recordAll() before using other RecordingContext static methods';
} else if (RecordingContext.recorders.length == 0) {
throw 'Called a RecordingContext method, but no canvases are being recorded.';

@@ -198,0 +323,0 @@ } else if (RecordingContext.recorders.length > 1) {

@@ -53,3 +53,3 @@ (function() {

expect(dtx2).to.equal(dtx2);
expect(dtx2).to.equal(dtx);
});

@@ -331,2 +331,3 @@

}).to.throw(/forgot.*reset/);
RecordingContext.reset();
});

@@ -337,5 +338,114 @@

RecordingContext.drawnObjects();
}).to.throw(/no canvases.*recorded/);
}).to.throw(/You must call .*recordAll/);
});
it('should throw on access with nothing recorded', function() {
expect(function() {
RecordingContext.recordAll();
RecordingContext.drawnObjects();
}).to.throw(/no canvases are being recorded/);
RecordingContext.reset();
});
});
describe('drawImage', function() {
beforeEach(function() {
RecordingContext.recordAll();
});
afterEach(function() {
RecordingContext.reset();
});
function makeOffscreenImage() {
var image = document.createElement('canvas');
image.width = 100;
image.height = 100;
var dtx = dataCanvas.getDataContext(image);
dtx.pushObject('A');
dtx.fillRect(0, 0, 50, 50);
dtx.popObject();
return image;
}
it('should transfer recorded calls', function() {
var image = makeOffscreenImage();
var dtx = dataCanvas.getDataContext(canvas);
dtx.drawImage(image, 0, 0);
expect(dtx.calls).to.have.length(3);
expect(dtx.drawnObjects()).to.deep.equal(['A']);
expect(dtx.callsOf('fillRect')).to.deep.equal([['fillRect', 0, 0, 50, 50]]);
// The drawImage call is elided.
// This could be changed -- either way would be reasonable.
expect(dtx.callsOf('drawImage')).to.deep.equal([]);
});
it('should translate recorded calls', function() {
var image = makeOffscreenImage();
var dtx = dataCanvas.getDataContext(canvas);
dtx.drawImage(image, 50, 0); // dx=50
expect(dtx.calls).to.have.length(3);
expect(dtx.callsOf('fillRect')).to.deep.equal([['fillRect', 50, 0, 50, 50]]);
});
it('should transform recorded calls', function() {
var image = makeOffscreenImage();
var dtx = dataCanvas.getDataContext(canvas);
dtx.drawImage(image, 50, 0, 75, 50); // dx=50, dWidth=75, dHeight=50
expect(dtx.calls).to.have.length(3);
expect(dtx.callsOf('fillRect')).to.deep.equal([['fillRect', 50, 0, 37.5, 25]]);
});
it('should support a source rectangle', function() {
var image = makeOffscreenImage();
var dtx = dataCanvas.getDataContext(canvas);
// This copies x=75-100 and y=50-100 from source to dest
dtx.drawImage(image, 25, 50, 75, 50, 0, 0, 75, 50);
expect(dtx.calls).to.have.length(3);
expect(dtx.callsOf('fillRect')).to.deep.equal([['fillRect', -25, -50, 50, 50]]);
});
it('should reject invalid drawImage calls', function() {
var image = makeOffscreenImage();
var dtx = dataCanvas.getDataContext(canvas);
expect(function() {
dtx.drawImage(image, 50, 0, 75); // four params, should be 3, 5 or 9
}).to.throw(); // exact error depends on browser
});
it('should transform paths', function() {
var image = makeOffscreenImage();
var ctx = dataCanvas.getDataContext(image);
ctx.beginPath();
ctx.moveTo(20, 10);
ctx.lineTo(30, 20);
ctx.quadraticCurveTo(50, 20, 40, 30);
ctx.closePath();
var dtx = dataCanvas.getDataContext(canvas);
dtx.drawImage(image, 0, 10, 50, 25); // dx=0, dy=10, dWidth=50, dHeight=25
expect(dtx.callsOf('moveTo')).to.deep.equal([['moveTo', 10, 12.5]]);
expect(dtx.callsOf('lineTo')).to.deep.equal([['lineTo', 15, 15]]);
expect(dtx.callsOf('quadraticCurveTo')).to.deep.equal(
[['quadraticCurveTo', 25, 15, 20, 17.5]]);
});
it('should not transfer calls from unrecorded canvases', function() {
var image = document.createElement('canvas');
image.width = 100;
image.height = 100;
image.getContext('2d').fillRect(0, 0, 100, 100);
var dtx = dataCanvas.getDataContext(canvas);
dtx.drawImage(image, 0, 0);
// The fillRect call should not be transferred over.
expect(dtx.callsOf('drawImage')).to.deep.equal(
[['drawImage', image, 0, 0]]);
expect(dtx.callsOf('fillRect')).to.deep.equal([]);
});
});
});

@@ -342,0 +452,0 @@ });

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc