Merge pull request #31 from ConradIrwin/commonjs

Make canvas2svg work with commonjs and jsdom
This commit is contained in:
Gabriel Hernandez 2015-09-09 12:05:36 -07:00
commit 92bed4b9d6
6 changed files with 110 additions and 51 deletions

View File

@ -80,6 +80,24 @@ You should now be able to select your new example from playground.html or see it
If you find a bug, or want to add functionality, please add a new test case and include it with your pull request.
Using with node.js
==================
You can use `canvas2svg` with node.js using [jsdom](https://github.com/tmpvar/jsdom) with [node-canvas](https://github.com/Automattic/node-canvas). To do this first create a new document object, and then create a new instance of `C2S` based on that document:
```javascript
var canvas = require('canvas'),
jsdom = require('jsdom'),
C2S = require('canvas2svg');
var document = jsdom.jsdom();
var ctx = new C2S({document: document});
// ... drawing code goes here ...
```
N.B. You may not need node-canvas for some simple operations when using jsdom >= 6.3.0, but it's still recommended that you install it.
Updates
==========
- v1.0.15 Setup travis, add testharness and debug playground, and fix regression for __createElement refactor
@ -103,6 +121,17 @@ Misc
==========
Some canvas 2d context methods are not implemented yet. Watch out for setTransform and arcTo.
Releasing
=========
To release a new version:
* Run `gulp bump` to update the version number
* Add a new entry to the [Updates](#Updates) table
* `git commit -am v1.0.xx`
* `git push`
* `npm publish`
License
==========
This library is licensed under the MIT license.

5
bower.json Normal file
View File

@ -0,0 +1,5 @@
{
"name": "canvas2svg",
"version": "1.0.14",
"main": "./canvas2svg.js"
}

View File

@ -72,29 +72,6 @@
return mapping[textBaseline] || mapping.alphabetic;
}
/**
* Creates the specified svg element
* @private
*/
function createElement(elementName, properties, resetFill) {
if (typeof properties === "undefined") {
properties = {};
}
var element = document.createElementNS("http://www.w3.org/2000/svg", elementName),
keys = Object.keys(properties), i, key;
if(resetFill) {
//if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black.
element.setAttribute("fill", "none");
element.setAttribute("stroke", "none");
}
for(i=0; i<keys.length; i++) {
key = keys[i];
element.setAttribute(key, properties[key]);
}
return element;
}
// Unpack entities lookup where the numbers are in radix 32 to reduce the size
// entity mapping courtesy of tinymce
namedEntities = createNamedToNumberedLookup(
@ -198,15 +175,16 @@
* @param gradientNode - reference to the gradient
* @constructor
*/
CanvasGradient = function(gradientNode) {
CanvasGradient = function(gradientNode, ctx) {
this.__root = gradientNode;
this.__ctx = ctx;
};
/**
* Adds a color stop to the gradient root
*/
CanvasGradient.prototype.addColorStop = function(offset, color) {
var stop = createElement("stop"), regex, matches;
var stop = this.__ctx.__createElement("stop"), regex, matches;
stop.setAttribute("offset", offset);
if(color.indexOf("rgba") !== -1) {
//separate alpha value, since webkit can't handle it
@ -231,10 +209,11 @@
* width - width of your canvas (defaults to 500)
* height - height of your canvas (defaults to 500)
* enableMirroring - enables canvas mirroring (get image data) (defaults to false)
* document - the document object (defaults to the current document)
*/
ctx = function(o) {
var defaultOptions = { width:500, height:500, enableMirroring : false }, options;
var defaultOptions = { width:500, height:500, enableMirroring : false}, options;
//keep support for this way of calling C2S: new C2S(width,height)
if(arguments.length > 1) {
@ -258,7 +237,8 @@
this.enableMirroring = options.enableMirroring !== undefined ? options.enableMirroring : defaultOptions.enableMirroring;
this.canvas = this; ///point back to this instance!
this.__canvas = document.createElement("canvas");
this.__document = options.document || document;
this.__canvas = this.__document.createElement("canvas");
this.__ctx = this.__canvas.getContext("2d");
this.__setDefaultStyles();
@ -266,7 +246,7 @@
this.__groupStack = [];
//the root svg element
this.__root = document.createElementNS("http://www.w3.org/2000/svg", "svg");
this.__root = this.__document.createElementNS("http://www.w3.org/2000/svg", "svg");
this.__root.setAttribute("version", 1.1);
this.__root.setAttribute("xmlns", "http://www.w3.org/2000/svg");
this.__root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
@ -277,14 +257,38 @@
this.__ids = {};
//defs tag
this.__defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
this.__defs = this.__document.createElementNS("http://www.w3.org/2000/svg", "defs");
this.__root.appendChild(this.__defs);
//also add a group child. the svg element can't use the transform attribute
this.__currentElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
this.__currentElement = this.__document.createElementNS("http://www.w3.org/2000/svg", "g");
this.__root.appendChild(this.__currentElement);
};
/**
* Creates the specified svg element
* @private
*/
ctx.prototype.__createElement = function (elementName, properties, resetFill) {
if (typeof properties === "undefined") {
properties = {};
}
var element = this.__document.createElementNS("http://www.w3.org/2000/svg", elementName),
keys = Object.keys(properties), i, key;
if(resetFill) {
//if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black.
element.setAttribute("fill", "none");
element.setAttribute("stroke", "none");
}
for(i=0; i<keys.length; i++) {
key = keys[i];
element.setAttribute(key, properties[key]);
}
return element;
};
/**
* Applies default canvas styles to the context
* @private
@ -426,7 +430,7 @@
* Will generate a group tag.
*/
ctx.prototype.save = function() {
var group = createElement("g"), parent = this.__closestGroupOrSvg();
var group = this.__createElement("g"), parent = this.__closestGroupOrSvg();
this.__groupStack.push(parent);
parent.appendChild(group);
this.__currentElement = group;
@ -451,7 +455,7 @@
//if the current element has siblings, add another group
var parent = this.__closestGroupOrSvg();
if(parent.childNodes.length > 0) {
var group = createElement("g");
var group = this.__createElement("g");
parent.appendChild(group);
this.__currentElement = group;
}
@ -509,7 +513,7 @@
this.__currentDefaultPath = "";
this.__currentPosition = {};
path = createElement("path", {}, true);
path = this.__createElement("path", {}, true);
parent = this.__closestGroupOrSvg();
parent.appendChild(path);
this.__currentElement = path;
@ -732,7 +736,7 @@
*/
ctx.prototype.fillRect = function(x, y, width, height){
var rect, parent;
rect = createElement("rect", {
rect = this.__createElement("rect", {
x : x,
y : y,
width : width,
@ -753,7 +757,7 @@
*/
ctx.prototype.strokeRect = function(x, y, width, height){
var rect, parent;
rect = createElement("rect", {
rect = this.__createElement("rect", {
x : x,
y : y,
width : width,
@ -771,7 +775,7 @@
*/
ctx.prototype.clearRect = function(x, y, width, height) {
var rect, parent = this.__closestGroupOrSvg();
rect = createElement("rect", {
rect = this.__createElement("rect", {
x : x,
y : y,
width : width,
@ -786,7 +790,7 @@
* Returns a canvas gradient object that has a reference to it's parent def
*/
ctx.prototype.createLinearGradient = function(x1, y1, x2, y2){
var grad = createElement("linearGradient", {
var grad = this.__createElement("linearGradient", {
id : randomString(this.__ids),
x1 : x1+"px",
x2 : x2+"px",
@ -795,7 +799,7 @@
"gradientUnits" : "userSpaceOnUse"
}, false);
this.__defs.appendChild(grad);
return new CanvasGradient(grad);
return new CanvasGradient(grad, this);
};
/**
@ -803,7 +807,7 @@
* Returns a canvas gradient object that has a reference to it's parent def
*/
ctx.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){
var grad = createElement("radialGradient", {
var grad = this.__createElement("radialGradient", {
id : randomString(this.__ids),
cx : x1+"px",
cy : y1+"px",
@ -813,7 +817,7 @@
"gradientUnits" : "userSpaceOnUse"
}, false);
this.__defs.appendChild(grad);
return new CanvasGradient(grad);
return new CanvasGradient(grad, this);
};
@ -855,7 +859,7 @@
*/
ctx.prototype.__wrapTextLink = function(font, element) {
if(font.href) {
var a = createElement("a");
var a = this.__createElement("a");
a.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", font.href);
a.appendChild(element);
return a;
@ -874,7 +878,7 @@
ctx.prototype.__applyText = function(text, x, y, action) {
var font = this.__parseFont(),
parent = this.__closestGroupOrSvg(),
textElement = createElement("text", {
textElement = this.__createElement("text", {
"font-family" : font.family,
"font-size" : font.size,
"font-style" : font.style,
@ -886,7 +890,7 @@
"dominant-baseline": getDominantBaseline(this.textBaseline)
}, true);
textElement.appendChild(document.createTextNode(text));
textElement.appendChild(this.__document.createTextNode(text));
this.__currentElement = textElement;
this.__applyStyleToCurrentElement(action);
parent.appendChild(this.__wrapTextLink(font,textElement));
@ -963,9 +967,9 @@
*/
ctx.prototype.clip = function(){
var group = this.__closestGroupOrSvg(),
clipPath = createElement("clipPath"),
clipPath = this.__createElement("clipPath"),
id = randomString(this.__ids),
newGroup = createElement("g");
newGroup = this.__createElement("g");
group.removeChild(this.__currentElement);
clipPath.setAttribute("id", id);
@ -1043,14 +1047,14 @@
this.__currentElement = currentElement;
} else if(image.nodeName === "CANVAS" || image.nodeName === "IMG") {
//canvas or image
svgImage = createElement("image");
svgImage = this.__createElement("image");
svgImage.setAttribute("width", dw);
svgImage.setAttribute("height", dh);
svgImage.setAttribute("preserveAspectRatio", "none");
if(sx || sy || sw !== image.width || sh !== image.height) {
//crop the image using a temporary canvas
canvas = document.createElement("canvas");
canvas = this.__document.createElement("canvas");
canvas.width = dw;
canvas.height = dh;
context = canvas.getContext("2d");
@ -1071,13 +1075,13 @@
* Generates a pattern tag
*/
ctx.prototype.createPattern = function(image, repetition){
var pattern = document.createElementNS("http://www.w3.org/2000/svg", "pattern"), id = randomString(this.__ids),
var pattern = this.__document.createElementNS("http://www.w3.org/2000/svg", "pattern"), id = randomString(this.__ids),
img;
pattern.setAttribute("id", id);
pattern.setAttribute("width", image.width);
pattern.setAttribute("height", image.height);
if(image.nodeName === "CANVAS" || image.nodeName === "IMG") {
img = document.createElementNS("http://www.w3.org/2000/svg", "image");
img = this.__document.createElementNS("http://www.w3.org/2000/svg", "image");
img.setAttribute("width", image.width);
img.setAttribute("height", image.height);
img.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
@ -1102,6 +1106,13 @@
ctx.prototype.setTransform = function(){};
//add options for alternative namespace
window.C2S = ctx;
if (typeof window === "object") {
window.C2S = ctx;
}
// CommonJS/Browserify
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = ctx;
}
}());

View File

@ -4,6 +4,7 @@ var gulp = require('gulp');
var fs = require('fs');
var path = require('path');
var cheerio = require('cheerio');
var bump = require('gulp-bump');
function updateExample(filename) {
@ -28,4 +29,10 @@ gulp.task('update_examples', function() {
updateExample('test/testrunner.html');
});
gulp.task('bump', function() {
gulp.src(["./package.json", "./bower.json"])
.pipe(bump({type:'patch'}))
.pipe(gulp.dest('./'));
});
gulp.task('default', ['update_examples']);

View File

@ -22,6 +22,7 @@
"chai": "^2.1.1",
"cheerio": "^0.19.0",
"gulp": "^3.9.0",
"gulp-bump": "^0.3.1",
"karma": "^0.12.36",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^0.1.12",

View File

@ -46,6 +46,12 @@ describe('canvas2svg', function() {
});
it("can be created on another document", function () {
var otherDoc = document.implementation.createHTMLDocument();
var ctx = C2S({document: otherDoc});
expect(ctx.getSvg().ownerDocument).to.equal(otherDoc);
});
});
describe("can export to", function() {