gerber-to-svg
Advanced tools
Comparing version 1.1.0 to 2.0.0
175
API.md
@@ -13,2 +13,6 @@ # gerber-to-svg API | ||
- [input](#input) | ||
- [options](#options) | ||
- [id and attributes options](#id-and-attributes-options) | ||
- [element options](#element-options) | ||
- [parsing and plotting options](#parsing-and-plotting-options) | ||
- [streaming API](#streaming-api) | ||
@@ -21,8 +25,2 @@ - [callback API](#callback-api) | ||
- [output](#output) | ||
- [options](#options) | ||
- [id option](#id-option) | ||
- [class option](#class-option) | ||
- [color option](#color-option) | ||
- [pretty option](#pretty-option) | ||
- [parsing and plotting options](#parsing-and-plotting-options) | ||
- [public properties](#public-properties) | ||
@@ -56,2 +54,75 @@ - [parser and plotter](#parser-and-plotter) | ||
### options | ||
The function must be passed an options object or string. If passed a string, it will be used as the `options.attribute.id` value. You may also use `options.id` in place of `options.attributes.id`. An `id` must be defined. The following options are available: | ||
**svg options** | ||
key | value | default | ||
-----------------|----------|-------------------------------------------------- | ||
id | String | See below | ||
attributes | Object | See below | ||
createElement | Function | [`xmlElementString`](./lib/xml-element-string) | ||
includeNamespace | Boolean | `true` | ||
objectMode | Boolean | false | ||
**parsing and plotting options** | ||
key | value | default | ||
--------------|---------------------|------------------ | ||
places | [int, int] | Parsed from file | ||
zero | 'L' or 'T' | Parsed from file | ||
filetype | 'gerber' or 'drill' | Parsed from file | ||
units | `mm` or `in` | Parsed from file | ||
backupUnits | `mm` or `in` | 'in' | ||
nota | `A` or `I` | Parsed from file | ||
backupNota | `A` or `I` | 'A' | ||
optimizePaths | `true` or `false` | `false` | ||
plotAsOutline | `true` or `false` | `false` | ||
#### id and attributes options | ||
The `id` and `attributes` options are used to set additional attributes of the top-level SVG node. Either the `id` option or `attributes.id` is required. `id` should be unique to avoid display problems with multiple SVGs on the same page. | ||
Some good candidates for other attributes to specify are: | ||
* `color` - Fills and strokes are set to `currentColor`, so setting color will change the color of the entire layer | ||
* `width` and `height` - By default, the width and height will be the real world dimensions of the layer, but you may want to set them to `100%` for display purposes | ||
* `class` or `className` (depending on your `createElement` function) - self explanatory | ||
#### element options | ||
`createElement`, `includeNamespace` and `objectMode` allow you to generate renders in a different format than the default XML string. `createElement` is a [hyperscript-style](https://github.com/dominictarr/hyperscript) function that takes a tagName, attributes map, and children array: | ||
``` javascript | ||
var defaultCreateElement = require('gerber-to-svg/lib/xml-elements-string') | ||
var customCreateElement = function(tagName, attributes, children) { | ||
// create an element somehow | ||
return 🍩 | ||
} | ||
``` | ||
The `includeNamespace` attribute is complementary to the `createElement` function, and determines whether the `xmlns: 'http://www.w3.org/2000/svg'` attribute will be included in or omitted from the `attributes` parameter of `createElement`. In certain virtual-dom implementations, you will need to set `includeNamespace` to `false` to avoid problems with `document.createElementNS`. | ||
`objectMode` needs to be set according to whether `createElement` returns a string (`objectMode: false`) or anything else (`objectMode: true`). If `objectMode` is set to true, the converter stream will be in [object mode](https://nodejs.org/api/stream.html#stream_object_mode) and emit objects instead of buffers. | ||
#### parsing and plotting options | ||
These options are available in case you have an older or poorly formatted file that does not contain the necessary format information and does not conform to the assumptions this library makes in the absence of that information. Some knowledge of the Gerber and Excellon formats are helpful when trying to understand these options. | ||
For more information, please reference the API documentation of [gerber-parser](https://github.com/mcous/gerber-parser/blob/master/API.md) and [gerber-plotter](https://github.com/mcous/gerber-plotter/blob/master/API.md), as these options are passed directly to these modules. | ||
key | description | ||
--------------|----------------------------------------------------------------------------- | ||
places | The number of places before and after the decimal used in coordinates | ||
zero | Leading or trailing zero suppression used in coordinates | ||
filetype | Whether to parse the file as a Gerber file or as a NC drill (Excellon) file | ||
units | Units of the file | ||
backupUnits | Backup units only to be used if units cannot be parsed from the file | ||
nota | Absolute or incremental coordinate notation | ||
backupNota | Backup notation only to be used if the notation cannot be parsed | ||
optimizePaths | Optimize trace paths by rearranging to occur in physical order | ||
plotAsOutline | Optimize and correct paths to better render the layer as a board outline | ||
## streaming API | ||
@@ -107,4 +178,9 @@ | ||
var gerberToSvg = require('gerber-to-svg') | ||
var cloneConverter = gerberToSvg.clone | ||
// or, for smaller builds | ||
var cloneConverter = require('gerber-to-svg/lib/clone') | ||
var converter = gerberToSvg(input, options, function(error, result) { | ||
var converterClone = gerberToSvg.clone(converter) | ||
var converterClone = cloneConverter(converter) | ||
storeSomehow(converterClone) | ||
@@ -116,12 +192,27 @@ }) | ||
Returns the SVG string from a completed converter or a clone of a completed converter. | ||
Returns the SVG from a completed converter or a clone of a completed `converter`. | ||
`gerberToSvg.render(converter, [id], [className], [color])` | ||
`gerberToSvg.render(converter, idOrAttributes, [createElement, includeNamespace])` | ||
* `converter` is the original gerber-to-svg converter or a clone of it | ||
* `idOrAttributes` is a string element id or an object of attributes | ||
* If it is an object, an `id` field is required | ||
* `createElement` is an optional function to use to create elements | ||
* Default: [`xml-element-string`](./lib/xml-element-string.js) | ||
* If used, must be the same `createElement` used in the original conversion | ||
* The API of `createElement` is [hyperscript style](https://github.com/dominictarr/hyperscript): (tag, attributes, children) => element | ||
* Can be used to create a VDOM element rather than an SVG string | ||
* `includeNamespace` is an optional flag that determines whether the xmlns attribute is passed to `createElement` (defaults to `true`) | ||
``` javascript | ||
var gerberToSvg = require('gerber-to-svg') | ||
var renderConverter = gerberToSvg.render | ||
// or, for smaller builds | ||
var renderConverter = require('gerber-to-svg/lib/render') | ||
var converter = getConverterCloneSomehow() | ||
var id = 'my-cool-id' | ||
var svgString = gerberToSvg.render(converter, id) | ||
var svgString = renderConverter(converter, id) | ||
``` | ||
@@ -189,58 +280,2 @@ | ||
## options | ||
The function must be passed an options object or string. If passed a string, it will be used as the `id` option. If passed an object, the `id` key is required. The following options are available: | ||
**svg options** | ||
key | value | default | ||
-------|-----------|---------------- | ||
id | String | N/A (required) | ||
class | String | undefined | ||
color | CSS color | undefined | ||
**parsing and plotting options** | ||
key | value | default | ||
--------------|---------------------|------------------ | ||
places | [int, int] | Parsed from file | ||
zero | 'L' or 'T' | Parsed from file | ||
filetype | 'gerber' or 'drill' | Parsed from file | ||
units | `mm` or `in` | Parsed from file | ||
backupUnits | `mm` or `in` | 'in' | ||
nota | `A` or `I` | Parsed from file | ||
backupNota | `A` or `I` | 'A' | ||
optimizePaths | `true` or `false` | `false` | ||
plotAsOutline | `true` or `false` | `false` | ||
### id option | ||
The `id` option is used as the id of the SVG node. It is also used to determine the prefix to the ids of internal nodes. If you are generating SVGs for multiple Gerber files for display on the same page, it is important that each conversion is passed a unique ID. If they are not unique, there may be id collisions between SVGs, and things could get weird. Any periods (`.`) in the id will be replaced with dashes (`-`). | ||
### class option | ||
The `class` option adds a class to the SVG node. Any periods (`.`) in the classname will be replaced with dashes (`-`). | ||
### color option | ||
The `color` option is a CSS color that will be used as the `fill` and `stroke` value of the image. The default value of 'currentColor' means the color will be defined by the CSS `color` property of the SVG. | ||
### pretty option | ||
If `pretty` is non-zero, the SVG string will be pretty-printed with tab-sizes equal to the number that was input. | ||
### parsing and plotting options | ||
These options are available in case you have an older or poorly formatted file that does not contain the necessary format information and does not conform to the assumptions this library makes in the absence of that information. Some knowledge of the Gerber and Excellon formats are helpful when trying to understand these options. | ||
key | description | ||
------------|----------------------------------------------------------------------------- | ||
places | The number of places before and after the decimal used in coordinates | ||
zero | Leading or trailing zero suppression used in coordinates | ||
filetype | Whether to parse the file as a Gerber file or as a NC drill (Excellon) file | ||
units | Units of the file | ||
backupUnits | Backup units only to be used if units cannot be parsed from the file | ||
nota | Absolute or incremental coordinate notation | ||
backupNota | Backup notation only to be used if the notation cannot be parsed | ||
## public properties | ||
@@ -254,4 +289,4 @@ | ||
plotter | `gerber-plotter` plotter | ||
defs | String | ||
layer | String | ||
defs | Array | ||
layer | Array | ||
viewBox | Array | ||
@@ -268,7 +303,7 @@ width | String | ||
The interior (innerText) of the `defs` node of the SVG. This is where pad shapes and clear layers will be defined. | ||
An array of the interior elements of the `defs` node of the SVG. This is where pad shapes and clear layers will be defined. | ||
### layer | ||
The interior of the top-level `g` node of the SVG. This is where regions, strokes, and flashes of dark layers will be. If there are clear layers, there may be nested `g` nodes with `mask` attributes inside `layer`. If no image was produces, this property will be falsey. | ||
An array of the interior elements of the top-level `g` node of the SVG. This is where regions, strokes, and flashes of dark layers will be. If there are clear layers, there may be nested `g` nodes with `mask` attributes inside `layer`. If no image was produces, this array will be empty. | ||
@@ -275,0 +310,0 @@ ### viewBox |
// create a path from a fill or stroke object | ||
'use strict' | ||
var reduce = require('lodash.reduce') | ||
var util = require('./_util') | ||
var shift = util.shift | ||
var xmlNode = util.xmlNode | ||
@@ -20,2 +17,3 @@ var pointsEqual = function(point, target) { | ||
var cmd = (lastCmd === 'L' || lastCmd === 'M') ? '' : 'L ' | ||
return (cmd + shift(end[0]) + ' ' + shift(end[1])) | ||
@@ -36,7 +34,9 @@ } | ||
var arc2 = arc('A', radius, Math.PI, dir, end, center) | ||
return arc1 + ' ' + arc2 | ||
} | ||
var result = (lastCmd === 'A') ? '' : 'A ' | ||
radius = shift(radius) | ||
var result = (lastCmd === 'A') ? '' : 'A ' | ||
result += radius + ' ' + radius + ' 0 ' | ||
@@ -82,10 +82,12 @@ result += ((sweep > Math.PI) ? '1 ' : '0 ') | ||
var createPath = function(segments, width) { | ||
var pathData = reduce(segments, reduceSegments, {last: [], data: ''}).data | ||
var fill = (width != null) ? 'none' : null | ||
width = (width != null) ? shift(width) : null | ||
module.exports = function createPath(segments, width, element) { | ||
var pathData = segments.reduce(reduceSegments, {last: [], data: ''}).data | ||
var attr = {d: pathData} | ||
return xmlNode('path', true, {d: pathData, fill: fill, 'stroke-width': width}) | ||
if (width != null) { | ||
attr.fill = 'none' | ||
attr['stroke-width'] = shift(width) | ||
} | ||
return element('path', attr) | ||
} | ||
module.exports = createPath |
@@ -6,10 +6,7 @@ // creates the SVG for a pad flash | ||
var shift = util.shift | ||
var xmlNode = util.xmlNode | ||
var flashPad = function(prefix, tool, x, y) { | ||
module.exports = function flashPad(prefix, tool, x, y, element) { | ||
var toolId = '#' + prefix + '_pad-' + tool | ||
return xmlNode('use', true, {'xlink:href': toolId, x: shift(x), y: shift(y)}) | ||
return element('use', {'xlink:href': toolId, x: shift(x), y: shift(y)}) | ||
} | ||
module.exports = flashPad |
// reduce a shape array into a string to place is defs | ||
'use strict' | ||
var reduce = require('lodash.reduce') | ||
var util = require('./_util') | ||
var shift = util.shift | ||
var xmlNode = util.xmlNode | ||
var startMask = util.startMask | ||
var createMask = util.createMask | ||
var maskLayer = util.maskLayer | ||
var circle = function(id, cx, cy, r, width) { | ||
width = (width != null) ? shift(width) : null | ||
var fill = (width != null) ? 'none' : null | ||
var element = function(tag, attr, children) { | ||
return {tag: tag, attr: attr, children: children || []} | ||
} | ||
return xmlNode('circle', true, { | ||
id: id, | ||
var circle = function(cx, cy, r, width) { | ||
var attr = { | ||
cx: shift(cx), | ||
cy: shift(cy), | ||
r: shift(r), | ||
'stroke-width': width, | ||
fill: fill | ||
}) | ||
r: shift(r) | ||
} | ||
if (width != null) { | ||
attr['stroke-width'] = shift(width) | ||
attr.fill = 'none' | ||
} | ||
return element('circle', attr) | ||
} | ||
var rect = function(id, cx, cy, r, width, height) { | ||
r = (r) ? shift(r) : null | ||
return xmlNode('rect', true, { | ||
id: id, | ||
var rect = function(cx, cy, r, width, height) { | ||
var attr = { | ||
x: shift(cx - width / 2), | ||
y: shift(cy - height / 2), | ||
rx: r, | ||
ry: r, | ||
width: shift(width), | ||
height: shift(height) | ||
}) | ||
} | ||
} | ||
var polyPoints = function(result, point, i, points) { | ||
var pointString = shift(point[0]) + ',' + shift(point[1]) | ||
return (result + pointString + ((i < (points.length - 1)) ? ' ' : '')) | ||
if (r) { | ||
attr.rx = shift(r) | ||
attr.ry = shift(r) | ||
} | ||
return element('rect', attr) | ||
} | ||
var poly = function(id, points) { | ||
return xmlNode('polygon', true, {id: id, points: reduce(points, polyPoints, '')}) | ||
var poly = function(points) { | ||
var pointsAttr = points.map(function(point) { | ||
return point.map(shift).join(',') | ||
}).join(' ') | ||
return element('polygon', {points: pointsAttr}) | ||
} | ||
var clip = function(id, shapes, ring) { | ||
var maskId = id + '_mask' | ||
var clip = function(maskIdPrefix, index, shapes, ring, createElement) { | ||
var maskId = maskIdPrefix + 'mask-' + index | ||
var maskUrl = 'url(#' + maskId + ')' | ||
var mask = xmlNode('mask', false, {id: maskId, stroke: '#fff'}) | ||
mask += circle(null, ring.cx, ring.cy, ring.r, ring.width) + '</mask>' | ||
var group = reduce(shapes, function(result, shape) { | ||
if (shape.type === 'rect') { | ||
return (result + rect(null, shape.cx, shape.cy, shape.r, shape.width, shape.height)) | ||
} | ||
var circleNode = circle(ring.cx, ring.cy, ring.r, ring.width) | ||
return (result + poly(null, shape.points)) | ||
}, xmlNode('g', false, {id: id, mask: maskUrl})) | ||
var mask = createElement( | ||
'mask', | ||
{id: maskId, stroke: '#fff'}, | ||
[createElement(circleNode.tag, circleNode.attr)]) | ||
return mask + group + '</g>' | ||
var groupChildren = shapes.map(function(shape) { | ||
var node = (shape.type === 'rect') | ||
? rect(shape.cx, shape.cy, shape.r, shape.width, shape.height) | ||
: poly(shape.points) | ||
return createElement(node.tag, node.attr) | ||
}) | ||
var layer = element('g', {mask: maskUrl}, groupChildren) | ||
return {mask: mask, layer: layer} | ||
} | ||
var reduceShapeArray = function(prefix, code, shapeArray) { | ||
module.exports = function reduceShapeArray(prefix, code, shapeArray, createElement) { | ||
var id = prefix + '_pad-' + code | ||
var maskIdPrefix = id + '_' | ||
var start = '' | ||
var end = '' | ||
if (shapeArray.length > 1) { | ||
start = xmlNode('g', false, {id: id}) | ||
end = '</g>' | ||
id = null | ||
} | ||
var image = reduce(shapeArray, function(result, shape) { | ||
var image = shapeArray.reduce(function(result, shape, index) { | ||
var svg | ||
@@ -83,19 +85,22 @@ | ||
case 'circle': | ||
svg = circle(id, shape.cx, shape.cy, shape.r) | ||
svg = circle(shape.cx, shape.cy, shape.r) | ||
break | ||
case 'ring': | ||
svg = circle(id, shape.cx, shape.cy, shape.r, shape.width) | ||
svg = circle(shape.cx, shape.cy, shape.r, shape.width) | ||
break | ||
case 'rect': | ||
svg = rect(id, shape.cx, shape.cy, shape.r, shape.width, shape.height) | ||
svg = rect(shape.cx, shape.cy, shape.r, shape.width, shape.height) | ||
break | ||
case 'poly': | ||
svg = poly(id, shape.points) | ||
svg = poly(shape.points) | ||
break | ||
case 'clip': | ||
svg = clip(id, shape.shape, shape.clip) | ||
var clipNodes = clip(maskIdPrefix, index, shape.shape, shape.clip, createElement) | ||
result.masks.push(clipNodes.mask) | ||
svg = clipNodes.layer | ||
break | ||
@@ -106,31 +111,62 @@ | ||
result.last = shape.polarity | ||
// if the polarity is clear, wrap the group and start a mask | ||
if (shape.polarity === 'clear') { | ||
var nextMaskId = maskIdPrefix + result.count | ||
result.masks += startMask(nextMaskId, shape.box) | ||
result.layers = maskLayer(nextMaskId, result.layers) | ||
result.maskId = nextMaskId | ||
result.maskBox = shape.box.slice(0) | ||
result.maskChildren = [] | ||
result.layers = [maskLayer(nextMaskId, result.layers, createElement)] | ||
} | ||
else { | ||
result.masks += '</mask>' | ||
var mask = createMask( | ||
result.maskId, | ||
result.maskBox, | ||
result.maskChildren, | ||
createElement) | ||
result.masks.push(mask) | ||
} | ||
return result | ||
break | ||
} | ||
if (result.last === 'dark') { | ||
result.layers += svg | ||
if (svg) { | ||
if (shapeArray.length === 1) { | ||
svg.attr.id = id | ||
} | ||
var svgElement = createElement(svg.tag, svg.attr, svg.children) | ||
if (result.last === 'dark') { | ||
result.layers.push(svgElement) | ||
} | ||
else { | ||
result.maskChildren.push(svgElement) | ||
} | ||
} | ||
else { | ||
result.masks += svg | ||
} | ||
return result | ||
}, {count: 0, last: 'dark', layers: '', masks: ''}) | ||
}, { | ||
count: 0, | ||
last: 'dark', | ||
layers: [], | ||
maskId: '', | ||
maskBox: [], | ||
maskChildren: [], | ||
masks: []}) | ||
if (image.last === 'clear') { | ||
image.masks += '</mask>' | ||
image.masks.push(createMask( | ||
image.maskId, | ||
image.maskBox, | ||
image.maskChildren, | ||
createElement)) | ||
} | ||
return image.masks + start + image.layers + end | ||
if (shapeArray.length > 1) { | ||
image.layers = createElement('g', {id: id}, image.layers) | ||
} | ||
return image.masks.concat(image.layers) | ||
} | ||
module.exports = reduceShapeArray |
// helper utilities | ||
'use strict' | ||
var reduce = require('lodash.reduce') | ||
// shift the decimal place to SVG coordinates (units * 1000) | ||
@@ -12,20 +10,4 @@ // also round to 7 decimal places | ||
// create an attribute assignment for SVG | ||
var attr = function(attr, val) { | ||
return (attr + '="' + val + '"') | ||
} | ||
// create an open or closed xml node with attributes | ||
var xmlNode = function(name, close, attributes) { | ||
var start = '<' + name | ||
var end = (close) ? '/>' : '>' | ||
var middle = reduce(attributes, function(result, value, key) { | ||
return result + ((value != null) ? (' ' + attr(key, value)) : '') | ||
}, '') | ||
return start + middle + end | ||
} | ||
var boundingRect = function(box, fill) { | ||
return xmlNode('rect', true, { | ||
var boundingRect = function(box, fill, element) { | ||
return element('rect', { | ||
x: shift(box[0]), | ||
@@ -39,13 +21,13 @@ y: shift(box[1]), | ||
var maskLayer = function(maskId, layer) { | ||
var maskLayer = function(maskId, layer, element) { | ||
var maskUrl = 'url(#' + maskId + ')' | ||
return xmlNode('g', false, {mask: maskUrl}) + layer + '</g>' | ||
return element('g', {mask: maskUrl}, layer) | ||
} | ||
var startMask = function(maskId, box) { | ||
var mask = xmlNode('mask', false, {id: maskId, fill: '#000', stroke: '#000'}) | ||
mask += boundingRect(box, '#fff') | ||
var createMask = function(maskId, box, children, element) { | ||
children = [boundingRect(box, '#fff', element)].concat(children) | ||
var attributes = {id: maskId, fill: '#000', stroke: '#000'} | ||
return mask | ||
return element('mask', attributes, children) | ||
} | ||
@@ -55,5 +37,4 @@ | ||
shift: shift, | ||
xmlNode: xmlNode, | ||
maskLayer: maskLayer, | ||
startMask: startMask | ||
createMask: createMask | ||
} |
@@ -5,3 +5,2 @@ // gerber to svg transform stream | ||
var isString = require('lodash.isstring') | ||
var pick = require('lodash.pick') | ||
var gerberParser = require('gerber-parser') | ||
@@ -11,23 +10,36 @@ var gerberPlotter = require('gerber-plotter') | ||
var PlotterToSvg = require('./plotter-to-svg') | ||
var render = require('./_render') | ||
var render = require('./render') | ||
var clone = require('./clone') | ||
var xmlElementString = require('./xml-element-string') | ||
var parseOptions = function(options) { | ||
var optionsIsString = isString(options) | ||
if (options == null || (!optionsIsString && (options.id == null))) { | ||
throw new Error('id required for gerber-to-svg') | ||
var getAttributesFromOptions = function(options) { | ||
if (!options) { | ||
return {} | ||
} | ||
if (optionsIsString) { | ||
return {svg: {id: options.replace('.', '-')}} | ||
var attributes = options.attributes || {} | ||
if (isString(options)) { | ||
attributes.id = options | ||
} | ||
else if (options.id) { | ||
attributes.id = options.id | ||
} | ||
var id = options.id.replace('.', '-') | ||
var className = options.class | ||
var color = options.color | ||
return attributes | ||
} | ||
var parseOptions = function(options) { | ||
var attributes = getAttributesFromOptions(options) | ||
if (!attributes.id) { | ||
throw new Error('Non-empty id required for gerber-to-svg') | ||
} | ||
var opts = { | ||
svg: { | ||
id: id, | ||
class: className, | ||
color: color | ||
attributes: attributes, | ||
createElement: options.createElement || xmlElementString, | ||
includeNamespace: (options.includeNamespace == null) ? true : options.includeNamespace, | ||
objectMode: (options.objectMode == null) ? false : options.objectMode | ||
}, | ||
@@ -56,3 +68,8 @@ parser: { | ||
var converter = new PlotterToSvg(opts.svg.id, opts.svg.class, opts.svg.color) | ||
var converter = new PlotterToSvg( | ||
opts.svg.attributes, | ||
opts.svg.createElement, | ||
opts.svg.includeNamespace, | ||
opts.svg.objectMode) | ||
var parser = gerberParser(opts.parser) | ||
@@ -106,2 +123,3 @@ var plotter = gerberPlotter(opts.plotter) | ||
var data | ||
do { | ||
@@ -117,2 +135,3 @@ data = converter.read() || '' | ||
converter.removeListener('end', finishConversion) | ||
return done(error) | ||
@@ -126,5 +145,2 @@ }) | ||
module.exports.render = render | ||
module.exports.clone = function cloneConverter(converter) { | ||
return pick(converter, ['defs', 'layer', 'viewBox', 'width', 'height', 'units']) | ||
} | ||
module.exports.clone = clone |
@@ -6,5 +6,3 @@ // transform stream to take plotter objects and convert them to an SVG string | ||
var inherits = require('inherits') | ||
var every = require('lodash.every') | ||
var isFinite = require('lodash.isfinite') | ||
var map = require('lodash.map') | ||
@@ -15,8 +13,7 @@ var reduceShapeArray = require('./_reduce-shape') | ||
var util = require('./_util') | ||
var render = require('./_render') | ||
var render = require('./render') | ||
var shift = util.shift | ||
var xmlNode = util.xmlNode | ||
var maskLayer = util.maskLayer | ||
var startMask = util.startMask | ||
var createMask = util.createMask | ||
@@ -27,7 +24,10 @@ var BLOCK_MODE_OFF = 0 | ||
var PlotterToSvg = function(id, className, color) { | ||
Transform.call(this, {writableObjectMode: true}) | ||
var PlotterToSvg = function(attributes, createElement, includeNamespace, objectMode) { | ||
Transform.call(this, { | ||
writableObjectMode: true, | ||
readableObjectMode: objectMode | ||
}) | ||
this.defs = '' | ||
this.layer = '' | ||
this.defs = [] | ||
this.layer = [] | ||
this.viewBox = [0, 0, 0, 0] | ||
@@ -38,6 +38,8 @@ this.width = 0 | ||
this._mask = '' | ||
this._maskId = '' | ||
this._maskBox = [] | ||
this._mask = [] | ||
this._blockMode = false | ||
this._blockBox = [] | ||
this._block = '' | ||
this._block = [] | ||
this._blockCount = 0 | ||
@@ -49,5 +51,8 @@ this._blockLayerCount = 0 | ||
this._blockCount = 0 | ||
this._id = id | ||
this._className = className | ||
this._color = color | ||
this._blockCount = 0 | ||
this._id = attributes.id | ||
this._attributes = attributes | ||
this._element = createElement | ||
this._includeNamespace = includeNamespace | ||
} | ||
@@ -60,15 +65,20 @@ | ||
case 'shape': | ||
this.defs += reduceShapeArray(this._id, chunk.tool, chunk.shape) | ||
this.defs = this.defs.concat(reduceShapeArray( | ||
this._id, | ||
chunk.tool, | ||
chunk.shape, | ||
this._element)) | ||
break | ||
case 'pad': | ||
this._draw(flashPad(this._id, chunk.tool, chunk.x, chunk.y)) | ||
this._draw(flashPad(this._id, chunk.tool, chunk.x, chunk.y, this._element)) | ||
break | ||
case 'fill': | ||
this._draw(createPath(chunk.path)) | ||
this._draw(createPath(chunk.path, null, this._element)) | ||
break | ||
case 'stroke': | ||
this._draw(createPath(chunk.path, chunk.width)) | ||
this._draw(createPath(chunk.path, chunk.width, this._element)) | ||
break | ||
@@ -95,4 +105,8 @@ | ||
this.push(render(this, this._id, this._className, this._color)) | ||
var attributes = this._attributes | ||
var element = this._element | ||
var includeNamespace = this._includeNamespace | ||
this.push(render(this, attributes, element, includeNamespace)) | ||
done() | ||
@@ -103,9 +117,10 @@ } | ||
// if there's a block, wrap it up, give it an id, and repeat it | ||
if (this._block) { | ||
if (this._block.length) { | ||
this._blockLayerCount++ | ||
var blockLayerId = this._id + '_block-' + this._blockCount + '-' + this._blockLayerCount | ||
this.defs += xmlNode('g', false, {id: blockLayerId}) + this._block + '</g>' | ||
this._block = '' | ||
this.defs.push(this._element('g', {id: blockLayerId}, this._block)) | ||
this._block = [] | ||
} | ||
@@ -115,5 +130,8 @@ } | ||
PlotterToSvg.prototype._finishClearLayer = function() { | ||
if (this._mask) { | ||
this.defs += this._mask + '</mask>' | ||
this._mask = '' | ||
if (this._maskId) { | ||
this.defs.push(createMask(this._maskId, this._maskBox, this._mask, this._element)) | ||
this._maskId = '' | ||
this._maskBox = [] | ||
this._mask = [] | ||
return true | ||
@@ -127,5 +145,8 @@ } | ||
if (this._blockMode) { | ||
if ((this._blockLayerCount === 0) && (this._block === '')) { | ||
this._blockMode = (polarity === 'dark') ? BLOCK_MODE_DARK : BLOCK_MODE_CLEAR | ||
if ((this._blockLayerCount === 0) && !this._block.length) { | ||
this._blockMode = (polarity === 'dark') | ||
? BLOCK_MODE_DARK | ||
: BLOCK_MODE_CLEAR | ||
} | ||
return this._finishBlockLayer() | ||
@@ -139,4 +160,5 @@ } | ||
if (polarity === 'clear') { | ||
this.layer = maskLayer(maskId, this.layer) | ||
this._mask = startMask(maskId, box) | ||
this.layer = [maskLayer(maskId, this.layer, this._element)] | ||
this._maskId = maskId | ||
this._maskBox = box.slice(0) | ||
} | ||
@@ -154,4 +176,7 @@ // else, finish the mask and add it to the defs | ||
var wasClear = this._finishClearLayer() | ||
this._finishBlockLayer() | ||
var layer = this.layer | ||
var element = this._element | ||
var blockMode = this._blockMode | ||
@@ -162,36 +187,44 @@ var blockLayers = this._blockLayerCount | ||
// add dark layers to layer | ||
this.layer += map(this._offsets, function(offset) { | ||
var result = '' | ||
this._offsets.forEach(function(offset) { | ||
for (var i = blockMode; i <= blockLayers; i += 2) { | ||
result += xmlNode('use', true, { | ||
layer.push(element('use', { | ||
'xlink:href': '#' + blockIdStart + i, | ||
x: shift(offset[0]), | ||
y: shift(offset[1]) | ||
}) | ||
})) | ||
} | ||
}) | ||
return result | ||
}).join('') | ||
// if there are clear layers in the block, mask the layer with them | ||
if (blockLayers > (2 - blockMode)) { | ||
var maskId = blockIdStart + 'clear' | ||
this.layer = maskLayer(maskId, this.layer) | ||
this._mask = startMask(maskId, this._blockBox) | ||
this._mask += map(this._offsets, function(offset) { | ||
var result = '' | ||
this.layer = [maskLayer(maskId, layer, this._element)] | ||
this._maskId = maskId | ||
this._maskBox = this._blockBox.slice(0) | ||
this._mask = this._offsets.reduce(function(result, offset) { | ||
var isDark | ||
for (var i = 1; i <= blockLayers; i++) { | ||
isDark = (blockMode === BLOCK_MODE_DARK) ? ((i % 2) === 1) : ((i % 2) === 0) | ||
result += xmlNode('use', true, { | ||
isDark = (blockMode === BLOCK_MODE_DARK) | ||
? ((i % 2) === 1) | ||
: ((i % 2) === 0) | ||
var attr = { | ||
'xlink:href': '#' + blockIdStart + i, | ||
x: shift(offset[0]), | ||
y: shift(offset[1]), | ||
fill: isDark ? '#fff' : null, | ||
stroke: isDark ? '#fff' : null | ||
}) | ||
y: shift(offset[1]) | ||
} | ||
if (isDark) { | ||
attr.fill = '#fff', | ||
attr.stroke = '#fff' | ||
} | ||
result.push(element('use', attr)) | ||
} | ||
return result | ||
}).join('') | ||
}, []) | ||
wasClear = this._finishClearLayer() | ||
@@ -206,3 +239,3 @@ } | ||
this._blockLayerCount = 0 | ||
this._blockBox = every(box, isFinite) ? box : [0, 0, 0, 0] | ||
this._blockBox = box.every(isFinite) ? box : [0, 0, 0, 0] | ||
} | ||
@@ -215,3 +248,3 @@ else { | ||
PlotterToSvg.prototype._handleSize = function(box, units) { | ||
if (every(box, isFinite)) { | ||
if (box.every(isFinite)) { | ||
var x = shift(box[0]) | ||
@@ -231,11 +264,11 @@ var y = shift(box[1]) | ||
if (!this._blockMode) { | ||
if (!this._mask) { | ||
this.layer += object | ||
if (!this._maskId) { | ||
this.layer.push(object) | ||
} | ||
else { | ||
this._mask += object | ||
this._mask.push(object) | ||
} | ||
} | ||
else { | ||
this._block += object | ||
this._block.push(object) | ||
} | ||
@@ -242,0 +275,0 @@ } |
{ | ||
"name": "gerber-to-svg", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "Gerber and NC drill file to SVG converter", | ||
@@ -71,11 +71,8 @@ "main": "lib/gerber-to-svg.js", | ||
"chalk": "^1.1.1", | ||
"escape-html": "^1.0.3", | ||
"gerber-parser": "^1.0.0", | ||
"gerber-plotter": "^1.0.0", | ||
"inherits": "^2.0.1", | ||
"lodash.every": "^4.3.0", | ||
"lodash.isfinite": "^3.2.0", | ||
"lodash.isstring": "^4.0.1", | ||
"lodash.map": "^4.3.0", | ||
"lodash.pick": "^4.2.0", | ||
"lodash.reduce": "^4.3.0", | ||
"minimist": "^1.1.0", | ||
@@ -82,0 +79,0 @@ "mkdirp": "^0.5.1", |
@@ -5,12 +5,13 @@ // test suite for gerber-to-svg | ||
var events = require('events') | ||
var proxyquire = require('proxyquire') | ||
var assign = require('lodash.assign') | ||
var sinon = require('sinon') | ||
var chai = require('chai') | ||
var sinonChai = require('sinon-chai') | ||
var proxyquire = require('proxyquire') | ||
var assign = require('lodash.assign') | ||
var expect = chai.expect | ||
var expect = chai.expect | ||
chai.use(sinonChai) | ||
var render = require('../lib/_render') | ||
var render = require('../lib/render') | ||
var clone = require('../lib/clone') | ||
@@ -20,6 +21,8 @@ var parserStub = sinon.stub() | ||
var converterStub = sinon.stub() | ||
var xmlElementSpy = sinon.spy(require('../lib/xml-element-string')) | ||
var gerberToSvg = proxyquire('../lib/gerber-to-svg', { | ||
'gerber-parser': parserStub, | ||
'gerber-plotter': plotterStub, | ||
'./plotter-to-svg': converterStub | ||
'./plotter-to-svg': converterStub, | ||
'./xml-element-string': xmlElementSpy | ||
}) | ||
@@ -68,4 +71,5 @@ | ||
var converter1 = gerberToSvg('', 'test-id') | ||
var converter2 = gerberToSvg('', 'test-id', function() {}) | ||
expect(converter1).to.equal(fakeConverter) | ||
var converter2 = gerberToSvg('', 'test-id', function() {}) | ||
expect(converter2).to.equal(fakeConverter) | ||
@@ -98,8 +102,8 @@ | ||
var input = {pipe: sinon.spy(), setEncoding: sinon.spy()} | ||
gerberToSvg(input, 'test-id') | ||
expect(input.pipe).to.have.been.calledWith(fakeParser) | ||
expect(fakeParser.pipe).to.have.been.calledWith(fakePlotter) | ||
expect(fakePlotter.pipe).to.have.been.calledWith(fakeConverter) | ||
expect(input.setEncoding).to.have.been.calledWith('utf8') | ||
expect(input.pipe).to.be.calledWith(fakeParser) | ||
expect(fakeParser.pipe).to.be.calledWith(fakePlotter) | ||
expect(fakePlotter.pipe).to.be.calledWith(fakeConverter) | ||
expect(input.setEncoding).to.be.calledWith('utf8') | ||
}) | ||
@@ -109,6 +113,7 @@ | ||
var input = 'G04 empty gerber*\nM02*\n' | ||
gerberToSvg(input, 'test-id') | ||
setTimeout(function() { | ||
expect(fakeParser.write).to.have.been.calledWith(input) | ||
expect(fakeParser.write).to.be.calledWith(input) | ||
expect(fakeParser.end).to.have.been.calledOnce | ||
@@ -121,3 +126,3 @@ done() | ||
gerberToSvg('', 'foo') | ||
expect(converterStub).to.have.been.calledWith('foo') | ||
expect(converterStub).to.be.calledWith({id: 'foo'}) | ||
}) | ||
@@ -127,3 +132,3 @@ | ||
gerberToSvg('', {id: 'bar'}) | ||
expect(converterStub).to.have.been.calledWith('bar') | ||
expect(converterStub).to.be.calledWith({id: 'bar'}) | ||
}) | ||
@@ -133,19 +138,37 @@ | ||
expect(function() {gerberToSvg('', {})}).to.throw(/id required/) | ||
expect(function() {gerberToSvg('')}).to.throw(/id required/) | ||
}) | ||
it('should replace dots in the id with dashed', function() { | ||
gerberToSvg('', 'hello.world') | ||
expect(converterStub).to.have.been.calledWith('hello-world') | ||
it('should pass the attributes option', function() { | ||
gerberToSvg('', {id: 'foo', attributes: {bar: 'baz'}}) | ||
expect(converterStub).to.be.calledWith({id: 'foo', bar: 'baz'}) | ||
}) | ||
it('should pass the class option', function() { | ||
gerberToSvg('', {id: 'foo', class: 'bar'}) | ||
expect(converterStub).to.have.been.calledWith('foo', 'bar') | ||
it('should pass createElement, which should default to xml-element-string', function() { | ||
var element = function() {} | ||
gerberToSvg('', {id: 'foo'}) | ||
expect(converterStub).to.be.calledWith({id: 'foo'}, xmlElementSpy) | ||
gerberToSvg('', {id: 'bar', createElement: element}) | ||
expect(converterStub).to.be.calledWith({id: 'bar'}, element) | ||
}) | ||
it('should pass the color option', function() { | ||
gerberToSvg('', {id: 'foo', color: 'red'}) | ||
expect(converterStub).to.have.been.calledWith('foo', undefined, 'red') | ||
it('should pass includeNamespace, which should default true', function() { | ||
var element = function() {} | ||
gerberToSvg('', {id: 'foo', createElement: element}) | ||
expect(converterStub).to.be.calledWith({id: 'foo'}, element, true) | ||
gerberToSvg('', {id: 'bar', createElement: element, includeNamespace: false}) | ||
expect(converterStub).to.be.calledWith({id: 'bar'}, element, false) | ||
}) | ||
it('should pass objectMode, which should default to false', function() { | ||
var element = function() {} | ||
gerberToSvg('', {id: 'foo', createElement: element}) | ||
expect(converterStub).to.be.calledWith({id: 'foo'}, element, true, false) | ||
gerberToSvg('', {id: 'bar', createElement: element, objectMode: true}) | ||
expect(converterStub).to.be.calledWith({id: 'bar'}, element, true, true) | ||
}) | ||
describe('passing along warnings', function() { | ||
@@ -200,2 +223,3 @@ it('should emit warnings from the parser', function(done) { | ||
var expectedError = {} | ||
gerberToSvg('foobar*\n', 'foobar', function(error) { | ||
@@ -211,2 +235,3 @@ expect(error).to.equal(expectedError) | ||
var expectedError = {} | ||
gerberToSvg('foobar*\n', 'foobar', function(error) { | ||
@@ -223,2 +248,3 @@ expect(error).to.equal(expectedError) | ||
var parser = new events.EventEmitter | ||
assign(parser, fakeParser, {format: {filetype: 'foobar'}}) | ||
@@ -228,2 +254,3 @@ parserStub.returns(parser) | ||
var converter = gerberToSvg('G04 a gerber file*\n', 'gbr') | ||
expect(converter.filetype).to.be.falsey | ||
@@ -237,4 +264,4 @@ | ||
var fakeConverter = { | ||
defs: 'the', | ||
layer: 'other', | ||
defs: ['the'], | ||
layer: ['other'], | ||
viewBox: [0, 1, 2, 3], | ||
@@ -247,6 +274,7 @@ width: 'I', | ||
expect(String(gerberToSvg.render)).to.equal(String(render)) | ||
expect(gerberToSvg.render(fakeConverter)).to.equal(expected) | ||
}) | ||
it('shoud have a clone method that clones the public properties of a converter', function() { | ||
it('shoud have a clone method that clones public properties of a converter', function() { | ||
var converter = { | ||
@@ -267,2 +295,3 @@ parser: 'hello', | ||
expect(String(gerberToSvg.clone)).to.equal(String(clone)) | ||
expect(gerberToSvg.clone(converter)).to.eql({ | ||
@@ -286,5 +315,5 @@ defs: 'the', | ||
} | ||
gerberToSvg('foo*\n', options) | ||
expect(parserStub).to.have.been.calledWith({ | ||
expect(parserStub).to.be.calledWith({ | ||
places: [2, 3], | ||
@@ -306,5 +335,5 @@ zero: 'T', | ||
} | ||
gerberToSvg('foo*\n', options) | ||
expect(plotterStub).to.have.been.calledWith({ | ||
expect(plotterStub).to.be.calledWith({ | ||
units: 'in', | ||
@@ -311,0 +340,0 @@ backupUnits: 'mm', |
// test suite for the plotter to svg transform stream | ||
'use strict' | ||
var expect = require('chai').expect | ||
var assign = require('lodash.assign') | ||
var sinon = require('sinon') | ||
var chai = require('chai') | ||
var sinonChai = require('sinon-chai') | ||
var expect = chai.expect | ||
chai.use(sinonChai) | ||
var PlotterToSvg = require('../lib/plotter-to-svg') | ||
var xmlElement = require('../lib/xml-element-string') | ||
var HALF_PI = Math.PI / 2 | ||
var EMPTY_SVG = [ | ||
'<svg id="id" ', | ||
'xmlns="http://www.w3.org/2000/svg" ', | ||
'version="1.1" ', | ||
'xmlns:xlink="http://www.w3.org/1999/xlink" ', | ||
'stroke-linecap="round" ', | ||
'stroke-linejoin="round" ', | ||
'stroke-width="0" ', | ||
'fill-rule="evenodd" ', | ||
'width="0" ', | ||
'height="0" ', | ||
'viewBox="0 0 0 0">', | ||
'</svg>'].join('') | ||
var SVG_ATTR = { | ||
id: 'id', | ||
xmlns: 'http://www.w3.org/2000/svg', | ||
version: '1.1', | ||
'xmlns:xlink': 'http://www.w3.org/1999/xlink', | ||
'stroke-linecap': 'round', | ||
'stroke-linejoin': 'round', | ||
'stroke-width': '0', | ||
'fill-rule': 'evenodd', | ||
width: '0', | ||
height: '0', | ||
viewBox: '0 0 0 0' | ||
} | ||
var EMPTY_BOX = [Infinity, Infinity, -Infinity, -Infinity] | ||
describe('plotter to svg transform stream', function() { | ||
var p | ||
var element | ||
beforeEach(function() { | ||
p = new PlotterToSvg('id') | ||
element = sinon.spy(xmlElement) | ||
p = new PlotterToSvg({id: 'id'}, element) | ||
p.setEncoding('utf8') | ||
@@ -31,4 +44,4 @@ }) | ||
it('should emit an empty svg if it gets a zero size plot', function(done) { | ||
p.once('data', function(result) { | ||
expect(result).to.equal(EMPTY_SVG) | ||
p.once('data', function() { | ||
expect(element).to.be.calledWith('svg', SVG_ATTR, []) | ||
expect(p.viewBox).to.eql([0, 0, 0, 0]) | ||
@@ -41,3 +54,3 @@ expect(p.width).to.equal(0) | ||
p.write({type: 'size', box: [Infinity, Infinity, -Infinity, -Infinity], units: ''}) | ||
p.write({type: 'size', box: EMPTY_BOX, units: ''}) | ||
p.end() | ||
@@ -47,32 +60,35 @@ }) | ||
it('should be able to add an id', function(done) { | ||
p = new PlotterToSvg('foo') | ||
p.once('data', function(result) { | ||
expect(result).to.match(/id="foo"/) | ||
var converter = new PlotterToSvg({id: 'foo'}, element) | ||
var expected = assign({}, SVG_ATTR, {id: 'foo'}) | ||
converter.once('data', function() { | ||
expect(element).to.be.calledWith('svg', expected) | ||
done() | ||
}) | ||
p.write({type: 'size', box: [Infinity, Infinity, -Infinity, -Infinity], units: ''}) | ||
p.end() | ||
converter.write({type: 'size', box: EMPTY_BOX, units: ''}) | ||
converter.end() | ||
}) | ||
it('should be able to add a classname', function(done) { | ||
p = new PlotterToSvg('foo', 'bar') | ||
p.once('data', function(result) { | ||
expect(result).to.match(/class="bar"/) | ||
it('should be able to add other attributes', function(done) { | ||
var converter = new PlotterToSvg({id: 'foo', bar: 'baz'}, element) | ||
var expected = assign({}, SVG_ATTR, {id: 'foo', bar: 'baz'}) | ||
converter.once('data', function() { | ||
expect(element).to.be.calledWith('svg', expected) | ||
done() | ||
}) | ||
p.write({type: 'size', box: [Infinity, Infinity, -Infinity, -Infinity], units: ''}) | ||
p.end() | ||
converter.write({type: 'size', box: EMPTY_BOX, units: ''}) | ||
converter.end() | ||
}) | ||
it('should be able to add a color', function(done) { | ||
p = new PlotterToSvg('foo', 'bar', 'baz') | ||
p.setEncoding('utf8') | ||
p.once('data', function(result) { | ||
expect(result).to.match(/color="baz"/) | ||
it('should be able to omit the namespace from attributes', function(done) { | ||
p = new PlotterToSvg({id: 'id'}, element, false) | ||
p.once('data', function() { | ||
expect(element.firstCall.args[1].xmlns).to.not.exist | ||
done() | ||
}) | ||
p.write({type: 'size', box: [Infinity, Infinity, -Infinity, -Infinity], units: ''}) | ||
p.write({type: 'size', box: EMPTY_BOX, units: ''}) | ||
p.end() | ||
@@ -84,6 +100,7 @@ }) | ||
var toolShape = [{type: 'circle', cx: 0.001, cy: 0.002, r: 0.005}] | ||
var expected = '<circle id="id_pad-10" cx="1" cy="2" r="5"/>' | ||
var expected = {id: 'id_pad-10', cx: 1, cy: 2, r: 5} | ||
p.write({type: 'shape', tool: '10', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('circle', expected) | ||
expect(p.defs).to.eql([element.returnValues[0]]) | ||
}) | ||
@@ -95,6 +112,7 @@ | ||
] | ||
var expected = '<rect id="id_pad-10" x="1" y="2" rx="2" ry="2" width="2" height="4"/>' | ||
var expected = {id: 'id_pad-10', x: 1, y: 2, rx: 2, ry: 2, width: 2, height: 4} | ||
p.write({type: 'shape', tool: '10', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('rect', expected) | ||
expect(p.defs).to.eql([element.returnValues[0]]) | ||
}) | ||
@@ -104,6 +122,7 @@ | ||
var toolShape = [{type: 'poly', points: [[0, 0], [1, 0], [0, 1]]}] | ||
var expected = '<polygon id="id_pad-12" points="0,0 1000,0 0,1000"/>' | ||
var expected = {id: 'id_pad-12', points: '0,0 1000,0 0,1000'} | ||
p.write({type: 'shape', tool: '12', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('polygon', expected) | ||
expect(p.defs).to.eql([element.returnValues[0]]) | ||
}) | ||
@@ -113,7 +132,12 @@ | ||
var toolShape = [{type: 'ring', r: 0.02, width: 0.005, cx: 0.05, cy: -0.03}] | ||
var expected = '<circle id="id_pad-11" cx="50" cy="-30" r="20" ' | ||
expected += 'stroke-width="5" fill="none"/>' | ||
var expected = { | ||
id: 'id_pad-11', | ||
cx: 50, cy: -30, r: 20, | ||
'stroke-width': 5, | ||
fill: 'none' | ||
} | ||
p.write({type: 'shape', tool: '11', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('circle', expected) | ||
expect(p.defs).to.eql([element.returnValues[0]]) | ||
}) | ||
@@ -128,19 +152,24 @@ | ||
] | ||
var ring = {type: 'ring', r: 0.004, width: 0.002, cx: 0, cy: 0} | ||
var toolShape = [{type: 'clip', shape: clippedShapes, clip: ring}] | ||
var expected = [ | ||
'<mask id="id_pad-15_mask" stroke="#fff">', | ||
'<circle cx="0" cy="0" r="4" stroke-width="2" fill="none"/>', | ||
'</mask>', | ||
'<g id="id_pad-15" mask="url(#id_pad-15_mask)">', | ||
'<rect x="1" y="1" width="4" height="4"/>', | ||
'<rect x="-5" y="1" width="4" height="4"/>', | ||
'<rect x="-5" y="-5" width="4" height="4"/>', | ||
'<rect x="1" y="-5" width="4" height="4"/>', | ||
'</g>' | ||
].join('') | ||
{cx: 0, cy: 0, r: 4, 'stroke-width': 2, fill: 'none'}, | ||
{id: 'id_pad-15_mask-0', stroke: '#fff'}, | ||
{x: 1, y: 1, width: 4, height: 4}, | ||
{x: -5, y: 1, width: 4, height: 4}, | ||
{x: -5, y: -5, width: 4, height: 4}, | ||
{x: 1, y: -5, width: 4, height: 4}, | ||
{id: 'id_pad-15', mask: 'url(#id_pad-15_mask-0)'} | ||
] | ||
p.write({type: 'shape', tool: '15', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('circle', expected[0]) | ||
expect(element).to.be.calledWith('mask', expected[1], [element.returnValues[0]]) | ||
expect(element).to.be.calledWith('rect', expected[2]) | ||
expect(element).to.be.calledWith('rect', expected[3]) | ||
expect(element).to.be.calledWith('rect', expected[4]) | ||
expect(element).to.be.calledWith('rect', expected[5]) | ||
expect(element).to.be.calledWith('g', expected[6], element.returnValues.slice(2, 6)) | ||
expect(p.defs).to.eql([element.returnValues[1], element.returnValues[6]]) | ||
}) | ||
@@ -162,17 +191,21 @@ | ||
var toolShape = [{type: 'clip', shape: clippedShapes, clip: ring}] | ||
var expected = [ | ||
'<mask id="id_pad-15_mask" stroke="#fff">', | ||
'<circle cx="0" cy="0" r="4" stroke-width="2" fill="none"/>', | ||
'</mask>', | ||
'<g id="id_pad-15" mask="url(#id_pad-15_mask)">', | ||
'<polygon points="1,1 5,1 5,5 1,5"/>', | ||
'<polygon points="-5,1 -1,1 -1,5 -5,5"/>', | ||
'<polygon points="-5,-5 -1,-5 -1,-1 -5,-1"/>', | ||
'<polygon points="1,-5 5,-5 5,-1 1,-1"/>', | ||
'</g>' | ||
].join('') | ||
{cx: 0, cy: 0, r: 4, 'stroke-width': 2, fill: 'none'}, | ||
{id: 'id_pad-15_mask-0', stroke: '#fff'}, | ||
{points: '1,1 5,1 5,5 1,5'}, | ||
{points: '-5,1 -1,1 -1,5 -5,5'}, | ||
{points: '-5,-5 -1,-5 -1,-1 -5,-1'}, | ||
{points: '1,-5 5,-5 5,-1 1,-1'}, | ||
{id: 'id_pad-15', mask: 'url(#id_pad-15_mask-0)'} | ||
] | ||
p.write({type: 'shape', tool: '15', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('circle', expected[0]) | ||
expect(element).to.be.calledWith('mask', expected[1], [element.returnValues[0]]) | ||
expect(element).to.be.calledWith('polygon', expected[2]) | ||
expect(element).to.be.calledWith('polygon', expected[3]) | ||
expect(element).to.be.calledWith('polygon', expected[4]) | ||
expect(element).to.be.calledWith('polygon', expected[5]) | ||
expect(element).to.be.calledWith('g', expected[6], element.returnValues.slice(2, 6)) | ||
expect(p.defs).to.eql([element.returnValues[1], element.returnValues[6]]) | ||
}) | ||
@@ -189,14 +222,79 @@ | ||
var expected = [ | ||
'<g id="id_pad-20">', | ||
'<rect x="1" y="1" width="4" height="4"/>', | ||
'<rect x="-5" y="1" width="4" height="4"/>', | ||
'<rect x="-5" y="-5" width="4" height="4"/>', | ||
'<rect x="1" y="-5" width="4" height="4"/>', | ||
'</g>' | ||
].join('') | ||
{x: 1, y: 1, width: 4, height: 4}, | ||
{x: -5, y: 1, width: 4, height: 4}, | ||
{x: -5, y: -5, width: 4, height: 4}, | ||
{x: 1, y: -5, width: 4, height: 4}, | ||
{id: 'id_pad-20'} | ||
] | ||
p.write({type: 'shape', tool: '20', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
expect(element).to.be.calledWith('rect', expected[0]) | ||
expect(element).to.be.calledWith('rect', expected[1]) | ||
expect(element).to.be.calledWith('rect', expected[2]) | ||
expect(element).to.be.calledWith('rect', expected[3]) | ||
expect(element).to.be.calledWith('g', expected[4], element.returnValues.slice(0, 4)) | ||
expect(p.defs).to.eql([element.returnValues[4]]) | ||
}) | ||
it('should handle multiple clipped primitives', function() { | ||
var clippedShapes1 = [ | ||
{type: 'rect', cx: 0.003, cy: 0.003, width: 0.004, height: 0.004, r: 0}, | ||
{type: 'rect', cx: -0.003, cy: 0.003, width: 0.004, height: 0.004, r: 0}, | ||
{type: 'rect', cx: -0.003, cy: -0.003, width: 0.004, height: 0.004, r: 0}, | ||
{type: 'rect', cx: 0.003, cy: -0.003, width: 0.004, height: 0.004, r: 0} | ||
] | ||
var clippedShapes2 = [ | ||
{type: 'rect', cx: 0.003, cy: 0.003, width: 0.002, height: 0.002, r: 0}, | ||
{type: 'rect', cx: -0.003, cy: 0.003, width: 0.002, height: 0.002, r: 0}, | ||
{type: 'rect', cx: -0.003, cy: -0.003, width: 0.002, height: 0.002, r: 0}, | ||
{type: 'rect', cx: 0.003, cy: -0.003, width: 0.002, height: 0.002, r: 0} | ||
] | ||
var ring1 = {type: 'ring', r: 0.004, width: 0.002, cx: 0, cy: 0} | ||
var ring2 = {type: 'ring', r: 0.002, width: 0.001, cx: 0, cy: 0} | ||
var toolShape = [ | ||
{type: 'clip', shape: clippedShapes1, clip: ring1}, | ||
{type: 'clip', shape: clippedShapes2, clip: ring2} | ||
] | ||
p.write({type: 'shape', tool: '15', shape: toolShape}) | ||
var values = element.returnValues | ||
var expected = [ | ||
{cx: 0, cy: 0, r: 4, 'stroke-width': 2, fill: 'none'}, | ||
{id: 'id_pad-15_mask-0', stroke: '#fff'}, | ||
{x: 1, y: 1, width: 4, height: 4}, | ||
{x: -5, y: 1, width: 4, height: 4}, | ||
{x: -5, y: -5, width: 4, height: 4}, | ||
{x: 1, y: -5, width: 4, height: 4}, | ||
{mask: 'url(#id_pad-15_mask-0)'}, | ||
{cx: 0, cy: 0, r: 2, 'stroke-width': 1, fill: 'none'}, | ||
{id: 'id_pad-15_mask-1', stroke: '#fff'}, | ||
{x: 2, y: 2, width: 2, height: 2}, | ||
{x: -4, y: 2, width: 2, height: 2}, | ||
{x: -4, y: -4, width: 2, height: 2}, | ||
{x: 2, y: -4, width: 2, height: 2}, | ||
{mask: 'url(#id_pad-15_mask-1)'}, | ||
{id: 'id_pad-15'} | ||
] | ||
expect(element).to.be.calledWith('circle', expected[0]) | ||
expect(element).to.be.calledWith('mask', expected[1], [values[0]]) | ||
expect(element).to.be.calledWith('rect', expected[2]) | ||
expect(element).to.be.calledWith('rect', expected[3]) | ||
expect(element).to.be.calledWith('rect', expected[4]) | ||
expect(element).to.be.calledWith('rect', expected[5]) | ||
expect(element).to.be.calledWith('g', expected[6], values.slice(2, 6)) | ||
expect(element).to.be.calledWith('circle', expected[7]) | ||
expect(element).to.be.calledWith('mask', expected[8], [values[7]]) | ||
expect(element).to.be.calledWith('rect', expected[9]) | ||
expect(element).to.be.calledWith('rect', expected[10]) | ||
expect(element).to.be.calledWith('rect', expected[11]) | ||
expect(element).to.be.calledWith('rect', expected[12]) | ||
expect(element).to.be.calledWith('g', expected[13], values.slice(9, 13)) | ||
expect(element).to.be.calledWith('g', expected[14], [values[6], values[13]]) | ||
expect(p.defs).to.eql([values[1], values[8], values[14]]) | ||
}) | ||
it('should handle polarity changes', function() { | ||
@@ -216,24 +314,35 @@ var toolShape = [ | ||
var expected = [ | ||
'<mask id="id_pad-11_1" fill="#000" stroke="#000">', | ||
'<rect x="-3" y="1" width="6" height="8" fill="#fff"/>', | ||
'<rect x="-2" y="3" width="4" height="4"/>', | ||
'</mask>', | ||
'<mask id="id_pad-11_3" fill="#000" stroke="#000">', | ||
'<rect x="-4" y="-9" width="8" height="13" fill="#fff"/>', | ||
'<rect x="-2" y="-7" width="4" height="4"/>', | ||
'<circle cx="0" cy="0" r="2"/>', | ||
'</mask>', | ||
'<g id="id_pad-11">', | ||
'<g mask="url(#id_pad-11_3)">', | ||
'<g mask="url(#id_pad-11_1)">', | ||
'<rect x="-3" y="1" width="6" height="8"/>', | ||
'</g>', | ||
'<rect x="-3" y="-9" width="6" height="8"/>', | ||
'<circle cx="0" cy="0" r="4"/>', | ||
'</g>', | ||
'</g>' | ||
].join('') | ||
{x: -3, y: 1, width: 6, height: 8}, | ||
{mask: 'url(#id_pad-11_1)'}, | ||
{x: -2, y: 3, width: 4, height: 4}, | ||
{x: -3, y: 1, width: 6, height: 8, fill: '#fff'}, | ||
{id: 'id_pad-11_1', fill: '#000', stroke: '#000'}, | ||
{x: -3, y: -9, width: 6, height: 8}, | ||
{cx: 0, cy: 0, r: 4}, | ||
{mask: 'url(#id_pad-11_3)'}, | ||
{x: -2, y: -7, width: 4, height: 4}, | ||
{cx: 0, cy: 0, r: 2}, | ||
{x: -4, y: -9, width: 8, height: 13, fill: '#fff'}, | ||
{id: 'id_pad-11_3', fill: '#000', stroke: '#000'}, | ||
{id: 'id_pad-11'} | ||
] | ||
p.write({type: 'shape', tool: '11', shape: toolShape}) | ||
expect(p.defs).to.equal(expected) | ||
var values = element.returnValues | ||
expect(element).to.be.calledWith('rect', expected[0]) | ||
expect(element).to.be.calledWith('g', expected[1], [values[0]]) | ||
expect(element).to.be.calledWith('rect', expected[2]) | ||
expect(element).to.be.calledWith('rect', expected[3]) | ||
expect(element).to.be.calledWith('mask', expected[4], [values[3], values[2]]) | ||
expect(element).to.be.calledWith('rect', expected[5]) | ||
expect(element).to.be.calledWith('circle', expected[6]) | ||
expect(element).to.be.calledWith('g', expected[7], [values[1], values[5], values[6]]) | ||
expect(element).to.be.calledWith('rect', expected[8]) | ||
expect(element).to.be.calledWith('circle', expected[9]) | ||
expect(element).to.be.calledWith('rect', expected[10]) | ||
expect(element).to.be.calledWith('mask', expected[11], [values[10], values[8], values[9]]) | ||
expect(element).to.be.calledWith('g', expected[12], [values[7]]) | ||
expect(p.defs).to.eql([values[4], values[11], values[12]]) | ||
}) | ||
@@ -244,6 +353,6 @@ }) | ||
var pad = {type: 'pad', tool: '24', x: 0.020, y: 0.050} | ||
var expected = '<use xlink:href="#id_pad-24" x="20" y="50"/>' | ||
p.write(pad) | ||
expect(p.layer).to.equal(expected) | ||
expect(element).to.be.calledWith('use', {'xlink:href': '#id_pad-24', x: 20, y: 50}) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -254,6 +363,6 @@ | ||
var fill = {type: 'fill', path: []} | ||
var expected = '<path d=""/>' | ||
p.write(fill) | ||
expect(p.layer).to.equal(expected) | ||
expect(element).to.be.calledWith('path', {d: ''}) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -263,6 +372,6 @@ | ||
var stroke = {type: 'stroke', path: [], width: 0.006} | ||
var expected = '<path d="" fill="none" stroke-width="6"/>' | ||
p.write(stroke) | ||
expect(p.layer).to.equal(expected) | ||
expect(element).to.be.calledWith('path', {d: '', fill: 'none', 'stroke-width': 6}) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -278,6 +387,7 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 0 0 100 0 100 100 0 100 0 0"' | ||
var expected = {d: 'M 0 0 100 0 100 100 0 100 0 0', fill: 'none', 'stroke-width': 6} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -292,6 +402,11 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 0 0 100 100 M 200 200 300 300 M 400 400 500 500"' | ||
var expected = { | ||
d: 'M 0 0 100 100 M 200 200 300 300 M 400 400 500 500', | ||
fill: 'none', | ||
'stroke-width': 6 | ||
} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -324,7 +439,12 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 100 0 A 100 100 0 0 1 0 100 100 100 0 1 1 100 0 ' | ||
expectedData += 'M 1100 0 A 100 100 0 1 0 1000 100 100 100 0 0 0 1100 0' | ||
var expectedData = [ | ||
'M 100 0 A 100 100 0 0 1 0 100 100 100 0 1 1 100 0', | ||
'M 1100 0 A 100 100 0 1 0 1000 100 100 100 0 0 0 1100 0' | ||
].join(' ') | ||
var expected = {d: expectedData, fill: 'none', 'stroke-width': 6} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -340,6 +460,7 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 0 0 0 0"' | ||
var expected = {d: 'M 0 0 0 0', fill: 'none', 'stroke-width': 6} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -355,6 +476,11 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 0 0 A 100 100 0 0 1 -200 0 100 100 0 0 1 0 0"' | ||
var expected = { | ||
d: 'M 0 0 A 100 100 0 0 1 -200 0 100 100 0 0 1 0 0', | ||
fill: 'none', | ||
'stroke-width': 6 | ||
} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -373,6 +499,11 @@ | ||
var stroke = {type: 'stroke', width: 0.006, path: path} | ||
var expectedData = 'd="M 100 0 A 100 100 0 0 1 -100 0 L 0 0"' | ||
var expected = { | ||
d: 'M 100 0 A 100 100 0 0 1 -100 0 L 0 0', | ||
fill: 'none', | ||
'stroke-width': 6 | ||
} | ||
p.write(stroke) | ||
expect(p.layer).to.include(expectedData) | ||
expect(element).to.be.calledWith('path', expected) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
@@ -383,49 +514,41 @@ }) | ||
it('should wrap the layer in a masked group when polarity becomes clear', function() { | ||
p.layer = '<path d="M 0 0 1 0 1 1 0 1 0 0"/>' | ||
var existing = ['<path d="M 0 0 1 0 1 1 0 1 0 0"/>'] | ||
var polarity = {type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]} | ||
var expected = '<g mask="url(#id_clear-1)"><path d="M 0 0 1 0 1 1 0 1 0 0"/></g>' | ||
p.layer = existing.slice(0) | ||
p.write(polarity) | ||
expect(p.layer).to.equal(expected) | ||
expect(element).to.be.calledWith('g', {mask: 'url(#id_clear-1)'}, existing) | ||
expect(p.layer).to.eql(element.returnValues) | ||
}) | ||
it('should start a mask when polarity becomes clear', function() { | ||
var polarity = {type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]} | ||
var expected = '<mask id="id_clear-1" fill="#000" stroke="#000">' | ||
expected += '<rect x="0" y="0" width="1000" height="1000" fill="#fff"/>' | ||
it('should construct a mask and add to defs when polarity switches back', function() { | ||
var clear = {type: 'polarity', polarity: 'clear', box: [0, 0, 0.5, 0.5]} | ||
var clearPad = {type: 'pad', tool: '10', x: 0.005, y: 0.005} | ||
var dark = {type: 'polarity', polarity: 'dark', box: [0, 0, 0.5, 0.5]} | ||
var darkPad = {type: 'pad', tool: '11', x: 0.005, y: 0.005} | ||
p.write(polarity) | ||
expect(p._mask).to.equal(expected) | ||
}) | ||
p.write(clear) | ||
p.write(clearPad) | ||
p.write(dark) | ||
p.write(darkPad) | ||
it('should write new shapes to the mask when polarity is clear', function() { | ||
var polarity = {type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]} | ||
var pad = {type: 'pad', tool: '10', x: 0.005, y: 0.005} | ||
var expected = '<mask id="id_clear-1" fill="#000" stroke="#000">' | ||
expected += '<rect x="0" y="0" width="1000" height="1000" fill="#fff"/>' | ||
expected += '<use xlink:href="#id_pad-10" x="5" y="5"/>' | ||
var values = element.returnValues | ||
var expected = [ | ||
{mask: 'url(#id_clear-1)'}, | ||
{'xlink:href': '#id_pad-10', x: 5, y: 5}, | ||
{x: 0, y: 0, width: 500, height: 500, fill: '#fff'}, | ||
{id: 'id_clear-1', fill: '#000', stroke: '#000'}, | ||
{'xlink:href': '#id_pad-11', x: 5, y: 5} | ||
] | ||
p.write(polarity) | ||
p.write(pad) | ||
expect(p.layer).to.equal('<g mask="url(#id_clear-1)"></g>') | ||
expect(p._mask).to.equal(expected) | ||
expect(element).to.be.calledWith('g', expected[0], []) | ||
expect(element).to.be.calledWith('use', expected[1]) | ||
expect(element).to.be.calledWith('rect', expected[2]) | ||
expect(element).to.be.calledWith('mask', expected[3], [values[2], values[1]]) | ||
expect(element).to.be.calledWith('use', expected[4]) | ||
expect(p._mask).to.eql([]) | ||
expect(p.defs).to.eql([values[3]]) | ||
expect(p.layer).to.eql([values[0], values[4]]) | ||
}) | ||
it('should finish the mask and add to defs when polarity switches back', function() { | ||
var clear = {type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]} | ||
var dark = {type: 'polarity', polarity: 'dark', box: [0, 0, 1, 1]} | ||
var pad = {type: 'pad', tool: '10', x: 0.005, y: 0.005} | ||
var expectedDefs = '<mask id="id_clear-1" fill="#000" stroke="#000">' | ||
expectedDefs += '<rect x="0" y="0" width="1000" height="1000" fill="#fff"/></mask>' | ||
var expectedLayer = '<g mask="url(#id_clear-1)"></g>' | ||
expectedLayer += '<use xlink:href="#id_pad-10" x="5" y="5"/>' | ||
p.write(clear) | ||
p.write(dark) | ||
p.write(pad) | ||
expect(p._mask).to.equal('') | ||
expect(p.defs).to.equal(expectedDefs) | ||
expect(p.layer).to.equal(expectedLayer) | ||
}) | ||
it('should not do anything with dark polarity if there is no mask', function() { | ||
@@ -435,5 +558,6 @@ var dark = {type: 'polarity', polarity: 'dark', box: [0, 0, 1, 1]} | ||
p.write(dark) | ||
expect(p._mask).to.equal('') | ||
expect(p.defs).to.equal('') | ||
expect(p.layer).to.equal('') | ||
expect(element).to.not.be.called | ||
expect(p._mask).to.eql([]) | ||
expect(p.defs).to.eql([]) | ||
expect(p.layer).to.eql([]) | ||
}) | ||
@@ -445,14 +569,22 @@ }) | ||
var offsets = [[0, 0], [0, 1], [1, 0], [1, 1]] | ||
var expected = [ | ||
{'xlink:href': '#id_pad-10', x: 250, y: 250}, | ||
{id: 'id_block-1-1'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 1000}, | ||
{'xlink:href': '#id_block-1-1', x: 1000, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 1000, y: 1000} | ||
] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 0.5, 0.5]}) | ||
p.write({type: 'pad', tool: '10', x: 0.25, y: 0.25}) | ||
p.write({type: 'repeat', offsets: [], box: [0, 0, 1.5, 1.5]}) | ||
expect(p.defs).to.equal( | ||
'<g id="id_block-1-1"><use xlink:href="#id_pad-10" x="250" y="250"/></g>') | ||
expect(p.layer).to.equal([ | ||
'<use xlink:href="#id_block-1-1" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="1000"/>', | ||
'<use xlink:href="#id_block-1-1" x="1000" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="1000" y="1000"/>' | ||
].join('')) | ||
expect(element).to.be.calledWith('use', expected[0]) | ||
expect(element).to.be.calledWith('g', expected[1], [element.returnValues[0]]) | ||
expect(element).to.be.calledWith('use', expected[2]) | ||
expect(element).to.be.calledWith('use', expected[3]) | ||
expect(element).to.be.calledWith('use', expected[4]) | ||
expect(element).to.be.calledWith('use', expected[5]) | ||
expect(p.defs).to.eql([element.returnValues[1]]) | ||
expect(p.layer).to.eql(element.returnValues.slice(2, 6)) | ||
}) | ||
@@ -462,2 +594,3 @@ | ||
var offsets = [[0, 0], [0, 5], [5, 0], [5, 5]] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 0.5, 0.5]}) | ||
@@ -475,48 +608,110 @@ p.write({type: 'pad', tool: '10', x: 0.25, y: 0.25}) | ||
expect(p.defs).to.equal([ | ||
'<g id="id_block-1-1"><use xlink:href="#id_pad-10" x="250" y="250"/></g>', | ||
'<g id="id_block-1-2"><use xlink:href="#id_pad-11" x="500" y="500"/></g>', | ||
'<g id="id_block-1-3"><use xlink:href="#id_pad-12" x="750" y="750"/></g>', | ||
'<g id="id_block-1-4"><use xlink:href="#id_pad-13" x="1000" y="1000"/></g>', | ||
'<g id="id_block-1-5"><use xlink:href="#id_pad-14" x="1250" y="1250"/></g>', | ||
'<mask id="id_block-1-clear" fill="#000" stroke="#000">', | ||
'<rect x="0" y="0" width="500" height="500" fill="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-3" x="0" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-4" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-5" x="0" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="5000" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="5000"/>', | ||
'<use xlink:href="#id_block-1-3" x="0" y="5000" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-4" x="0" y="5000"/>', | ||
'<use xlink:href="#id_block-1-5" x="0" y="5000" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="5000" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-2" x="5000" y="0"/>', | ||
'<use xlink:href="#id_block-1-3" x="5000" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-4" x="5000" y="0"/>', | ||
'<use xlink:href="#id_block-1-5" x="5000" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="5000" y="5000" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-2" x="5000" y="5000"/>', | ||
'<use xlink:href="#id_block-1-3" x="5000" y="5000" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-4" x="5000" y="5000"/>', | ||
'<use xlink:href="#id_block-1-5" x="5000" y="5000" fill="#fff" stroke="#fff"/>', | ||
'</mask>' | ||
].join('')) | ||
expect(p.layer).to.equal([ | ||
'<g mask="url(#id_block-1-clear)">', | ||
'<use xlink:href="#id_block-1-1" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-3" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-5" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="5000"/>', | ||
'<use xlink:href="#id_block-1-3" x="0" y="5000"/>', | ||
'<use xlink:href="#id_block-1-5" x="0" y="5000"/>', | ||
'<use xlink:href="#id_block-1-1" x="5000" y="0"/>', | ||
'<use xlink:href="#id_block-1-3" x="5000" y="0"/>', | ||
'<use xlink:href="#id_block-1-5" x="5000" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="5000" y="5000"/>', | ||
'<use xlink:href="#id_block-1-3" x="5000" y="5000"/>', | ||
'<use xlink:href="#id_block-1-5" x="5000" y="5000"/>', | ||
'</g>' | ||
].join('')) | ||
var values = element.returnValues | ||
var expected = [ | ||
{'xlink:href': '#id_pad-10', x: 250, y: 250}, | ||
{id: 'id_block-1-1'}, | ||
{'xlink:href': '#id_pad-11', x: 500, y: 500}, | ||
{id: 'id_block-1-2'}, | ||
{'xlink:href': '#id_pad-12', x: 750, y: 750}, | ||
{id: 'id_block-1-3'}, | ||
{'xlink:href': '#id_pad-13', x: 1000, y: 1000}, | ||
{id: 'id_block-1-4'}, | ||
{'xlink:href': '#id_pad-14', x: 1250, y: 1250}, | ||
{id: 'id_block-1-5'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-3', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-5', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 5000}, | ||
{'xlink:href': '#id_block-1-3', x: 0, y: 5000}, | ||
{'xlink:href': '#id_block-1-5', x: 0, y: 5000}, | ||
{'xlink:href': '#id_block-1-1', x: 5000, y: 0}, | ||
{'xlink:href': '#id_block-1-3', x: 5000, y: 0}, | ||
{'xlink:href': '#id_block-1-5', x: 5000, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 5000, y: 5000}, | ||
{'xlink:href': '#id_block-1-3', x: 5000, y: 5000}, | ||
{'xlink:href': '#id_block-1-5', x: 5000, y: 5000}, | ||
{mask: 'url(#id_block-1-clear)'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-3', x: 0, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-4', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-5', x: 0, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 5000}, | ||
{'xlink:href': '#id_block-1-3', x: 0, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-4', x: 0, y: 5000}, | ||
{'xlink:href': '#id_block-1-5', x: 0, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 5000, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-2', x: 5000, y: 0}, | ||
{'xlink:href': '#id_block-1-3', x: 5000, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-4', x: 5000, y: 0}, | ||
{'xlink:href': '#id_block-1-5', x: 5000, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 5000, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-2', x: 5000, y: 5000}, | ||
{'xlink:href': '#id_block-1-3', x: 5000, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-4', x: 5000, y: 5000}, | ||
{'xlink:href': '#id_block-1-5', x: 5000, y: 5000, fill: '#fff', stroke: '#fff'}, | ||
{x: 0, y: 0, width: 500, height: 500, fill: '#fff'}, | ||
{id: 'id_block-1-clear', fill: '#000', stroke: '#000'} | ||
] | ||
expect(element).to.be.calledWith('use', expected[0]) | ||
expect(element).to.be.calledWith('g', expected[1], [values[0]]) | ||
expect(element).to.be.calledWith('use', expected[2]) | ||
expect(element).to.be.calledWith('g', expected[3], [values[2]]) | ||
expect(element).to.be.calledWith('use', expected[4]) | ||
expect(element).to.be.calledWith('g', expected[5], [values[4]]) | ||
expect(element).to.be.calledWith('use', expected[6]) | ||
expect(element).to.be.calledWith('g', expected[7], [values[6]]) | ||
expect(element).to.be.calledWith('use', expected[8]) | ||
expect(element).to.be.calledWith('g', expected[9], [values[8]]) | ||
expect(element).to.be.calledWith('use', expected[10]) | ||
expect(element).to.be.calledWith('use', expected[11]) | ||
expect(element).to.be.calledWith('use', expected[12]) | ||
expect(element).to.be.calledWith('use', expected[13]) | ||
expect(element).to.be.calledWith('use', expected[14]) | ||
expect(element).to.be.calledWith('use', expected[15]) | ||
expect(element).to.be.calledWith('use', expected[16]) | ||
expect(element).to.be.calledWith('use', expected[17]) | ||
expect(element).to.be.calledWith('use', expected[18]) | ||
expect(element).to.be.calledWith('use', expected[19]) | ||
expect(element).to.be.calledWith('use', expected[20]) | ||
expect(element).to.be.calledWith('use', expected[21]) | ||
expect(element).to.be.calledWith('g', expected[22], values.slice(10, 22)) | ||
expect(element).to.be.calledWith('use', expected[23]) | ||
expect(element).to.be.calledWith('use', expected[24]) | ||
expect(element).to.be.calledWith('use', expected[25]) | ||
expect(element).to.be.calledWith('use', expected[26]) | ||
expect(element).to.be.calledWith('use', expected[27]) | ||
expect(element).to.be.calledWith('use', expected[28]) | ||
expect(element).to.be.calledWith('use', expected[29]) | ||
expect(element).to.be.calledWith('use', expected[30]) | ||
expect(element).to.be.calledWith('use', expected[31]) | ||
expect(element).to.be.calledWith('use', expected[32]) | ||
expect(element).to.be.calledWith('use', expected[33]) | ||
expect(element).to.be.calledWith('use', expected[34]) | ||
expect(element).to.be.calledWith('use', expected[35]) | ||
expect(element).to.be.calledWith('use', expected[36]) | ||
expect(element).to.be.calledWith('use', expected[37]) | ||
expect(element).to.be.calledWith('use', expected[38]) | ||
expect(element).to.be.calledWith('use', expected[39]) | ||
expect(element).to.be.calledWith('use', expected[40]) | ||
expect(element).to.be.calledWith('use', expected[41]) | ||
expect(element).to.be.calledWith('use', expected[42]) | ||
expect(element).to.be.calledWith('rect', expected[43]) | ||
expect(element).to.be.calledWith( | ||
'mask', | ||
expected[44], | ||
[values[43]].concat(values.slice(23, 43))) | ||
expect(p.defs).to.eql([ | ||
values[1], | ||
values[3], | ||
values[5], | ||
values[7], | ||
values[9], | ||
values[44] | ||
]) | ||
expect(p.layer).to.eql([values[22]]) | ||
}) | ||
@@ -526,6 +721,6 @@ | ||
var offsets = [[0, 0], [0, 0.5], [0.5, 0], [0.5, 0.5]] | ||
p.layer = 'SOME_EXISTING_STUFF' | ||
p.layer = ['LAYER'] | ||
p.write({type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]}) | ||
p._mask += 'SOME_EXISTING_CLEAR_STUFF' | ||
p._mask = ['MASK'] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 1, 1]}) | ||
@@ -537,32 +732,59 @@ p.write({type: 'pad', tool: '10', x: 0.25, y: 0.25}) | ||
expect(p.defs).to.equal([ | ||
'<mask id="id_clear-1" fill="#000" stroke="#000">', | ||
'<rect x="0" y="0" width="1000" height="1000" fill="#fff"/>', | ||
'SOME_EXISTING_CLEAR_STUFF', | ||
'</mask>', | ||
'<g id="id_block-1-1"><use xlink:href="#id_pad-10" x="250" y="250"/></g>', | ||
'<g id="id_block-1-2"><use xlink:href="#id_pad-11" x="250" y="250"/></g>', | ||
'<mask id="id_block-1-clear" fill="#000" stroke="#000">', | ||
'<rect x="0" y="0" width="1000" height="1000" fill="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="500"/>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="500" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="500" y="0"/>', | ||
'<use xlink:href="#id_block-1-2" x="500" y="0" fill="#fff" stroke="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="500" y="500"/>', | ||
'<use xlink:href="#id_block-1-2" x="500" y="500" fill="#fff" stroke="#fff"/>', | ||
'</mask>' | ||
].join('')) | ||
expect(p.layer).to.equal([ | ||
'<g mask="url(#id_block-1-clear)">', | ||
'<g mask="url(#id_clear-1)">', | ||
'SOME_EXISTING_STUFF', | ||
'</g>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-2" x="0" y="500"/>', | ||
'<use xlink:href="#id_block-1-2" x="500" y="0"/>', | ||
'<use xlink:href="#id_block-1-2" x="500" y="500"/>', | ||
'</g>' | ||
].join('')) | ||
var values = element.returnValues | ||
var expected = [ | ||
{mask: 'url(#id_block-1-clear)'}, | ||
{x: 0, y: 0, width: 1000, height: 1000, fill: '#fff'}, | ||
{id: 'id_clear-1', fill: '#000', stroke: '#000'}, | ||
{'xlink:href': '#id_pad-10', x: 250, y: 250}, | ||
{id: 'id_block-1-1'}, | ||
{'xlink:href': '#id_pad-11', x: 250, y: 250}, | ||
{id: 'id_block-1-2'}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 500}, | ||
{'xlink:href': '#id_block-1-2', x: 500, y: 0}, | ||
{'xlink:href': '#id_block-1-2', x: 500, y: 500}, | ||
{mask: 'url(#id_block-1-clear)'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 500}, | ||
{'xlink:href': '#id_block-1-2', x: 0, y: 500, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 500, y: 0}, | ||
{'xlink:href': '#id_block-1-2', x: 500, y: 0, fill: '#fff', stroke: '#fff'}, | ||
{'xlink:href': '#id_block-1-1', x: 500, y: 500}, | ||
{'xlink:href': '#id_block-1-2', x: 500, y: 500, fill: '#fff', stroke: '#fff'}, | ||
{x: 0, y: 0, width: 1000, height: 1000, fill: '#fff'}, | ||
{id: 'id_block-1-clear', fill: '#000', stroke: '#000'} | ||
] | ||
expect(element).to.be.calledWith('g', expected[0]) | ||
expect(element).to.be.calledWith('rect', expected[1]) | ||
expect(element).to.be.calledWith('mask', expected[2], [values[1], 'MASK']) | ||
expect(element).to.be.calledWith('use', expected[3]) | ||
expect(element).to.be.calledWith('g', expected[4], [values[3]]) | ||
expect(element).to.be.calledWith('use', expected[5]) | ||
expect(element).to.be.calledWith('g', expected[6], [values[5]]) | ||
expect(element).to.be.calledWith('use', expected[7]) | ||
expect(element).to.be.calledWith('use', expected[8]) | ||
expect(element).to.be.calledWith('use', expected[9]) | ||
expect(element).to.be.calledWith('use', expected[10]) | ||
expect(element).to.be.calledWith( | ||
'g', | ||
expected[11], | ||
[values[0]].concat(values.slice(7, 11))) | ||
expect(element).to.be.calledWith('use', expected[12]) | ||
expect(element).to.be.calledWith('use', expected[13]) | ||
expect(element).to.be.calledWith('use', expected[14]) | ||
expect(element).to.be.calledWith('use', expected[15]) | ||
expect(element).to.be.calledWith('use', expected[16]) | ||
expect(element).to.be.calledWith('use', expected[17]) | ||
expect(element).to.be.calledWith('use', expected[18]) | ||
expect(element).to.be.calledWith('use', expected[19]) | ||
expect(element).to.be.calledWith('rect', expected[20]) | ||
expect(element).to.be.calledWith( | ||
'mask', | ||
expected[21], | ||
[values[20]].concat(values.slice(12, 20))) | ||
expect(p.defs).to.eql([values[2], values[4], values[6], values[21]]) | ||
expect(p.layer).to.eql([values[11]]) | ||
}) | ||
@@ -572,3 +794,4 @@ | ||
var offsets = [[0, 0], [0, 0.5], [0.5, 0], [0.5, 0.5]] | ||
p.layer = 'SOME_EXISTING_STUFF' | ||
p.layer = ['SOME_EXISTING_STUFF'] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 1, 1]}) | ||
@@ -579,18 +802,48 @@ p.write({type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]}) | ||
expect(p.defs).to.equal([ | ||
'<g id="id_block-1-1"><use xlink:href="#id_pad-10" x="250" y="250"/></g>', | ||
'<mask id="id_block-1-clear" fill="#000" stroke="#000">', | ||
'<rect x="0" y="0" width="1000" height="1000" fill="#fff"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="500"/>', | ||
'<use xlink:href="#id_block-1-1" x="500" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="500" y="500"/>', | ||
'</mask>' | ||
].join('')) | ||
expect(p.layer).to.equal([ | ||
'<g mask="url(#id_block-1-clear)">', | ||
'SOME_EXISTING_STUFF', | ||
'</g>' | ||
].join('')) | ||
var values = element.returnValues | ||
var expected = [ | ||
{'xlink:href': '#id_pad-10', x: 250, y: 250}, | ||
{id: 'id_block-1-1'}, | ||
{mask: 'url(#id_block-1-clear)'}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 0, y: 500}, | ||
{'xlink:href': '#id_block-1-1', x: 500, y: 0}, | ||
{'xlink:href': '#id_block-1-1', x: 500, y: 500}, | ||
{x: 0, y: 0, width: 1000, height: 1000, fill: '#fff'}, | ||
{id: 'id_block-1-clear', fill: '#000', stroke: '#000'} | ||
] | ||
expect(element).to.be.calledWith('use', expected[0]) | ||
expect(element).to.be.calledWith('g', expected[1], [values[0]]) | ||
expect(element).to.be.calledWith('g', expected[2], ['SOME_EXISTING_STUFF']) | ||
expect(element).to.be.calledWith('use', expected[3]) | ||
expect(element).to.be.calledWith('use', expected[4]) | ||
expect(element).to.be.calledWith('use', expected[5]) | ||
expect(element).to.be.calledWith('use', expected[6]) | ||
expect(element).to.be.calledWith('rect', expected[7]) | ||
expect(element).to.be.calledWith('mask', expected[8], [values[7]].concat(values.slice(3, 7))) | ||
expect(p.defs).to.eql([values[1], values[8]]) | ||
expect(p.layer).to.eql([values[2]]) | ||
}) | ||
it('should handle polarity switches with no objects gracefully', function() { | ||
var offsets = [[0, 0], [0, 0.5], [0.5, 0], [0.5, 0.5]] | ||
p.layer = ['SOME_EXISTING_STUFF'] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 1, 1]}) | ||
p.write({type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]}) | ||
p.write({type: 'polarity', polarity: 'dark', box: [0, 0, 1, 1]}) | ||
p.write({type: 'polarity', polarity: 'clear', box: [0, 0, 1, 1]}) | ||
p.write({type: 'polarity', polarity: 'dark', box: [0, 0, 1, 1]}) | ||
expect(element).to.not.be.called | ||
}) | ||
it('should handle Infinities in the box', function() { | ||
var offsets = [[0, 0], [0, 0.5], [0.5, 0], [0.5, 0.5]] | ||
p.layer = ['SOME_EXISTING_STUFF'] | ||
p.write({type: 'repeat', offsets: offsets, box: EMPTY_BOX}) | ||
expect(p._blockBox).to.eql([0, 0, 0, 0]) | ||
}) | ||
}) | ||
@@ -611,21 +864,17 @@ | ||
var size = {type: 'size', box: [-1, -1, 1, 2], units: 'mm'} | ||
var expected = [ | ||
'<svg id="id" xmlns="http://www.w3.org/2000/svg" version="1.1" ', | ||
'xmlns:xlink="http://www.w3.org/1999/xlink" ', | ||
'stroke-linecap="round" stroke-linejoin="round" stroke-width="0" ', | ||
'fill-rule="evenodd" ', | ||
'width="2mm" height="3mm" viewBox="-1000 -1000 2000 3000">', | ||
'<defs>THESE_ARE_THE_DEFS</defs>', | ||
'<g transform="translate(0,1000) scale(1,-1)" ', | ||
'fill="currentColor" stroke="currentColor">THIS_IS_THE_clear</g>', | ||
'</svg>' | ||
].join('') | ||
var viewBox = '-1000 -1000 2000 3000' | ||
var transform = 'translate(0,1000) scale(1,-1)' | ||
var svgAttr = assign({}, SVG_ATTR, {width: '2mm', height: '3mm', viewBox: viewBox}) | ||
var layerAttr = {transform: transform, fill: 'currentColor', stroke: 'currentColor'} | ||
p.on('data', function(result) { | ||
expect(result).to.equal(expected) | ||
expect(element).to.be.calledWith('defs', {}, ['THESE_ARE_THE_DEFS']) | ||
expect(element).to.be.calledWith('g', layerAttr, ['THIS_IS_THE_LAYER']) | ||
expect(element).to.be.calledWith('svg', svgAttr, element.returnValues.slice(0, 2)) | ||
expect(result).to.equal(element.returnValues[2]) | ||
done() | ||
}) | ||
p.defs = 'THESE_ARE_THE_DEFS' | ||
p.layer = 'THIS_IS_THE_clear' | ||
p.defs = ['THESE_ARE_THE_DEFS'] | ||
p.layer = ['THIS_IS_THE_LAYER'] | ||
p.write(size) | ||
@@ -635,8 +884,23 @@ p.end() | ||
it('should omit the defs mode if it is empty', function(done) { | ||
var size = {type: 'size', box: [-1, -1, 1, 2], units: 'mm'} | ||
p.on('data', function() { | ||
expect(element).not.to.be.calledWith('defs') | ||
done() | ||
}) | ||
p.defs = [] | ||
p.layer = ['THIS_IS_THE_LAYER'] | ||
p.write(size) | ||
p.end() | ||
}) | ||
it('should finish any in-progress mask', function() { | ||
p._mask = '<mask id="id_clear-1">' | ||
p._maskId = 'id_clear-1' | ||
p._maskBox = [1, 2, 3, 4] | ||
p._mask = ['SOME STUFF'] | ||
p.end() | ||
expect(p._mask).to.equal('') | ||
expect(p.defs).to.equal('<mask id="id_clear-1"></mask>') | ||
expect(element).to.be.calledWith('mask', {id: 'id_clear-1', fill: '#000', stroke: '#000'}) | ||
}) | ||
@@ -646,2 +910,3 @@ | ||
var offsets = [[0, 0], [0, 1], [1, 0], [1, 1]] | ||
p.write({type: 'repeat', offsets: offsets, box: [0, 0, 0.5, 0.5]}) | ||
@@ -651,11 +916,8 @@ p.write({type: 'pad', tool: '10', x: 0.25, y: 0.25}) | ||
expect(p._block).to.equal('') | ||
expect(p.layer).to.equal([ | ||
'<use xlink:href="#id_block-1-1" x="0" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="0" y="1000"/>', | ||
'<use xlink:href="#id_block-1-1" x="1000" y="0"/>', | ||
'<use xlink:href="#id_block-1-1" x="1000" y="1000"/>' | ||
].join('')) | ||
expect(element).to.be.calledWith('use', {'xlink:href': '#id_block-1-1', x: 0, y: 0}) | ||
expect(element).to.be.calledWith('use', {'xlink:href': '#id_block-1-1', x: 0, y: 1000}) | ||
expect(element).to.be.calledWith('use', {'xlink:href': '#id_block-1-1', x: 1000, y: 0}) | ||
expect(element).to.be.calledWith('use', {'xlink:href': '#id_block-1-1', x: 1000, y: 1000}) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
215735
11
163
1859
+ Addedescape-html@^1.0.3
+ Addedescape-html@1.0.3(transitive)
- Removedlodash.every@^4.3.0
- Removedlodash.map@^4.3.0
- Removedlodash.pick@^4.2.0
- Removedlodash.reduce@^4.3.0
- Removedlodash.every@4.6.0(transitive)
- Removedlodash.map@4.6.0(transitive)
- Removedlodash.pick@4.4.0(transitive)