diff --git a/packages/core/src/config.mjs b/packages/core/src/config.mjs
index 9b775eb8e6c..bb599ccd49c 100644
--- a/packages/core/src/config.mjs
+++ b/packages/core/src/config.mjs
@@ -34,4 +34,5 @@ export const __loadPatternDefaults = () => ({
debug: false,
options: {},
absoluteOptions: {},
+ measurements: {}
})
diff --git a/packages/core/src/part.mjs b/packages/core/src/part.mjs
index 838a609b2c8..aba624a33a2 100644
--- a/packages/core/src/part.mjs
+++ b/packages/core/src/part.mjs
@@ -95,7 +95,6 @@ Part.prototype.setHidden = function (hidden = false) {
return this
}
-/** Returns an object with shorthand access for pattern design */
/**
* Returns an object that will be passed to draft method to be destructured
*
@@ -152,13 +151,13 @@ Part.prototype.shorthand = function () {
shorthand.Snippet.prototype = Object.create(Snippet.prototype)
// Proxy points, paths, snippets, measurements, options, and absoluteOptions
- shorthand.points = new Proxy(this.points || {}, pointsProxy(self.points, self.context.store.log))
- shorthand.paths = new Proxy(this.paths || {}, pathsProxy(self.paths, self.context.store.log))
+ shorthand.points = new Proxy(this.points, pointsProxy(self.points, self.context.store.log))
+ shorthand.paths = new Proxy(this.paths, pathsProxy(self.paths, self.context.store.log))
shorthand.snippets = new Proxy(
- this.snippets || {},
+ this.snippets,
snippetsProxy(self.snippets, self.context.store.log)
)
- shorthand.measurements = new Proxy(this.context.settings.measurements || {}, {
+ shorthand.measurements = new Proxy(this.context.settings.measurements, {
get: function (measurements, name) {
if (typeof measurements[name] === 'undefined')
self.context.store.log.warning(
@@ -168,7 +167,7 @@ Part.prototype.shorthand = function () {
},
set: (measurements, name, value) => (self.context.settings.measurements[name] = value),
})
- shorthand.options = new Proxy(this.context.settings.options || {}, {
+ shorthand.options = new Proxy(this.context.settings.options, {
get: function (options, name) {
if (typeof options[name] === 'undefined')
self.context.store.log.warning(
@@ -178,7 +177,7 @@ Part.prototype.shorthand = function () {
},
set: (options, name, value) => (self.context.settings.options[name] = value),
})
- shorthand.absoluteOptions = new Proxy(this.context.settings.absoluteOptions || {}, {
+ shorthand.absoluteOptions = new Proxy(this.context.settings.absoluteOptions, {
get: function (absoluteOptions, name) {
if (typeof absoluteOptions[name] === 'undefined')
self.context.store.log.warning(
@@ -239,9 +238,6 @@ Part.prototype.__boundary = function () {
}
} catch (err) {
this.context.store.log.error(`Could not calculate boundary of \`paths.${key}\``)
- this.context.store.log.debug(
- `Since \`paths.${key}\` has no boundary, neither does \`parts.${this.name}\`. Ejecting part`
- )
return false
}
}
diff --git a/packages/core/src/path.mjs b/packages/core/src/path.mjs
index 3689e6ae188..8e6f23954be 100644
--- a/packages/core/src/path.mjs
+++ b/packages/core/src/path.mjs
@@ -642,7 +642,7 @@ Path.prototype.shiftAlong = function (distance, stepsPerMm = 10) {
let thisLen = bezier.length()
if (Math.abs(len + thisLen - distance) < 0.1) return op.to
if (len + thisLen > distance)
- return shiftAlongBezier(distance - len, bezier, thisLen * stepsPerMm)
+ return __shiftAlongBezier(distance - len, bezier, thisLen * stepsPerMm)
len += thisLen
}
current = op.to
@@ -1266,25 +1266,10 @@ function __pathOffset(path, distance, log) {
* @private
* @param {float} distance - The distance to shift along the cubic Bezier curve
* @param {Bezier} bezier - The BezierJs instance
- * @param {int} steps - The numer of steps to walk the Bezier with
+ * @param {int} steps - The numer of steps per mm to walk the Bezier with
* @return {Point} point - The point at distance along the cubic Bezier curve
*/
-function shiftAlongBezier(distance, bezier, steps = false) {
- let rlen
- if (!steps) {
- rlen = new Path()
- .move(new Point(...Object.values(bezier.points[0])))
- .curve(
- new Point(...Object.values(bezier.points[1])),
- new Point(...Object.values(bezier.points[2])),
- new Point(...Object.values(bezier.points[3]))
- )
- .roughLength()
- if (rlen < 2) steps = 20
- else if (rlen < 10) steps = 40
- else if (rlen < 100) steps = 100
- else steps = 200
- }
+function __shiftAlongBezier(distance, bezier, steps) {
let previous, next, t, thisLen
let len = 0
for (let i = 0; i <= steps; i++) {
diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs
index f5d9e81a753..4d0b30cf606 100644
--- a/packages/core/src/pattern.mjs
+++ b/packages/core/src/pattern.mjs
@@ -334,7 +334,7 @@ Pattern.prototype.render = function () {
this.svg = new Svg(this)
this.svg.hooks = this.hooks
- return this.__pack().svg.render(this)
+ return this.__pack().svg.render()
}
/**
diff --git a/packages/core/src/svg.mjs b/packages/core/src/svg.mjs
index 4bd8b395984..7e25df2bb80 100644
--- a/packages/core/src/svg.mjs
+++ b/packages/core/src/svg.mjs
@@ -29,7 +29,7 @@ export function Svg(pattern) {
this.attributes.add('xmlns', 'http://www.w3.org/2000/svg')
this.attributes.add('xmlns:svg', 'http://www.w3.org/2000/svg')
this.attributes.add('xmlns:xlink', 'http://www.w3.org/1999/xlink')
- this.attributes.add('xml:lang', pattern.settings.locale)
+ this.attributes.add('xml:lang', pattern?.settings?.[0]?.locale || 'en')
this.attributes.add('xmlns:freesewing', 'http://freesewing.org/namespaces/freesewing')
this.attributes.add('freesewing', version)
}
@@ -44,21 +44,24 @@ export function Svg(pattern) {
* @param {Pattern} pattern - The pattern to render
* @return {string} svg - The rendered SVG output
*/
-Svg.prototype.render = function (pattern) {
- this.idPrefix = pattern.settings.idPrefix
+Svg.prototype.render = function () {
+ this.idPrefix = this.pattern?.settings?.[0]?.idPrefix || 'fs-'
this.__runHooks('preRender')
- pattern.__runHooks('postLayout')
- if (!pattern.settings.embed) {
- this.attributes.add('width', round(pattern.width) + 'mm')
- this.attributes.add('height', round(pattern.height) + 'mm')
+ this.pattern.__runHooks('postLayout')
+ if (!this.pattern.settings[0].embed) {
+ this.attributes.add('width', round(this.pattern.width) + 'mm')
+ this.attributes.add('height', round(this.pattern.height) + 'mm')
}
- this.attributes.add('viewBox', `0 0 ${pattern.width} ${pattern.height}`)
+ this.attributes.add('viewBox', `0 0 ${round(this.pattern.width)} ${round(this.pattern.height)}`)
this.head = this.__renderHead()
this.tail = this.__renderTail()
this.svg = ''
this.layout = {} // Reset layout
- for (let stackId in pattern.stacks) {
- const stack = pattern.stacks[stackId]
+ this.activeStackIndex = 0
+ for (let stackId in this.pattern.stacks) {
+ this.activeStack = stackId
+ this.idPrefix = this.pattern.settings[this.activeStackIndex].idPrefix
+ const stack = this.pattern.stacks[stackId]
if (!stack.hidden) {
const stackSvg = this.__renderStack(stack)
this.layout[stackId] = {
@@ -69,6 +72,7 @@ Svg.prototype.render = function (pattern) {
this.svg += stackSvg
this.svg += this.__closeGroup()
}
+ this.activeStackIndex++
}
this.svg = this.prefix + this.__renderSvgTag() + this.head + this.svg + this.tail
this.__runHooks('postRender')
@@ -137,7 +141,7 @@ Svg.prototype.__indent = function () {
Svg.prototype.__insertText = function (text) {
if (this.hooks.insertText.length > 0) {
for (let hook of this.hooks.insertText)
- text = hook.method(this.pattern.settings.locale, text, hook.data)
+ text = hook.method(this.pattern.settings[this.activeStackIndex].locale || 'en', text, hook.data)
}
return text
@@ -223,7 +227,6 @@ Svg.prototype.__renderDefs = function () {
*/
Svg.prototype.__renderHead = function () {
let svg = this.__renderStyle()
- svg += this.__renderScript()
svg += this.__renderDefs()
svg += this.__openGroup(this.idPrefix + 'container')
@@ -279,8 +282,8 @@ Svg.prototype.__renderPathText = function (path) {
* @param {Part} part - The Part instance to render
* @return {string} svg - The SVG markup for the Part object
*/
-Svg.prototype.__renderPart = function (part, partId) {
- let svg = this.__openGroup(`${this.idPrefix}part-${partId}`, part.attributes)
+Svg.prototype.__renderPart = function (part) {
+ let svg = this.__openGroup(`${this.idPrefix}stack-${this.activeStack}-part-${part.name}`, part.attributes)
for (let key in part.paths) {
let path = part.paths[key]
if (!path.hidden) svg += this.__renderPath(path)
@@ -302,22 +305,6 @@ Svg.prototype.__renderPart = function (part, partId) {
return svg
}
-/**
- * Returns SVG markup for the script block
- *
- * @private
- * @return {string} svg - The SVG markup for the script block
- */
-Svg.prototype.__renderScript = function () {
- let svg = '' + this.__nl()
-
- return svg
-}
-
/**
* Returns SVG markup for a snippet
*
diff --git a/packages/core/src/utils.mjs b/packages/core/src/utils.mjs
index 75fbba71db5..2d3535da39a 100644
--- a/packages/core/src/utils.mjs
+++ b/packages/core/src/utils.mjs
@@ -725,15 +725,10 @@ export const __addPartPlugins = (part, config, store) => {
store.log.debug(`🔌 __${plugin.name}__ plugin in \`${part.name}\``)
// Do not overwrite an existing plugin with a conditional plugin unless it is also conditional
if (plugin.plugin && plugin.condition) {
- if (plugins[plugin.plugin.name]?.condition) {
- store.log.info(
- `Plugin \`${plugin.plugin.name}\` was re-requested conditionally. Overwriting earlier condition.`
- )
- plugins[plugin.plugin.name] = plugin
- } else
- store.log.info(
- `Plugin \`${plugin.plugin.name}\` was requested conditionally, but is already loaded explicitly. Not loading.`
- )
+ if (plugins[plugin.plugin.name]?.condition) plugins[plugin.plugin.name] = plugin
+ else store.log.info(
+ `Plugin \`${plugin.plugin.name}\` was requested conditionally, but is already loaded explicitly. Not loading.`
+ )
} else {
plugins[plugin.name] = plugin
}
diff --git a/packages/core/tests/fixtures/render.mjs b/packages/core/tests/fixtures/render.mjs
index 776a20f6a7b..af1d7a9181c 100644
--- a/packages/core/tests/fixtures/render.mjs
+++ b/packages/core/tests/fixtures/render.mjs
@@ -3,366 +3,22 @@ import pkg from '../../package.json' assert { type: 'json' }
const { version } = pkg
var render = {
- boilerplate: ``,
- boilerplateNl: ``,
- embed: ``,
- part: ``,
- path: ``,
- text: ``,
- circle: ``,
- multiText: ``,
- multiTextDflt: ``,
- textOnPath: ``,
- textOnPathCenter: ``,
- textOnPathRight: ``,
- snippet: ``,
- rotatedSnippet: ``
+ boilerplate: ``,
+ boilerplateNl: ``,
+ embed: ``,
+ stack: ``,
+ part: ``,
+ path: ``,
+ text: `This is a test `,
+ multiText: `This is a testwith text onmultiple lines `,
+ multiTextDflt: `This is a testwith text onmultiple lines `,
+ textOnPath: `This is another test`,
+ textOnPathCenter: `This is another test`,
+ textOnPathRight: `This is another test`,
+ circle: ``,
+ snippet: ``,
+ rotatedSnippet: ``,
+ scaledSnippet: ``,
}
export default render
diff --git a/packages/core/tests/part.test.mjs b/packages/core/tests/part.test.mjs
index 5d3a05af7cf..72040cb1d31 100644
--- a/packages/core/tests/part.test.mjs
+++ b/packages/core/tests/part.test.mjs
@@ -1,5 +1,5 @@
import chai from 'chai'
-import { Design, Part } from '../src/index.mjs'
+import { Design, Part, pctBasedOn } from '../src/index.mjs'
const expect = chai.expect
@@ -75,6 +75,13 @@ describe('Part', () => {
expect(units(123.456)).to.equal('12.35cm')
})
+ it('Should convert units directly', () => {
+ const part = new Part()
+ part.context = { settings: { units: 'metric' } }
+ expect(part.units(123.456)).to.equal('12.35cm')
+ expect(part.units(123.456)).to.equal('12.35cm')
+ })
+
it('Should set part attributes', () => {
const part = new Part()
part.attr('foo', 'bar')
@@ -136,74 +143,27 @@ describe('Part', () => {
name: 'test',
draft: ({ points, Point, paths, Path, part }) => {
points.from = new Point(123, 456)
- points.to = new Point(19, 76)
+ points.to = new Point(19, 76).attr('data-circle', 12)
+
paths.test = new Path().move(points.from).line(points.to)
return part
},
}
const design = new Design({ parts: [part] })
const pattern = new design()
- pattern.draft()
+ pattern.draft().render()
const boundary = pattern.parts[0].test.__boundary()
const { topLeft, bottomRight, width, height } = boundary
- expect(topLeft.x).to.equal(19)
- expect(topLeft.y).to.equal(76)
+ expect(topLeft.x).to.equal(7)
+ expect(topLeft.y).to.equal(64)
+ // Cover the cached branch
+ pattern.parts[0].test.__boundary()
expect(bottomRight.x).to.equal(123)
expect(bottomRight.y).to.equal(456)
- expect(width).to.equal(104)
- expect(height).to.equal(380)
+ expect(width).to.equal(116)
+ expect(height).to.equal(392)
})
- /*
- it('Should stack a part', () => {
- const part = {
- name: 'test',
- draft: (part) => {
- const { points, Point, paths, Path } = part.shorthand()
- points.from = new Point(123, 456)
- points.to = new Point(19, 76)
- paths.test = new Path().move(points.from).line(points.to)
- return aprt
- }
- }
- const design = new Design({ parts: [ part ]})
- const pattern = new design({ paperless: true })
- pattern.draft()
- pattern.parts.test.home()
- console.log(pattern.parts.test.attributes)
- expect(part.attributes.get('transform')).to.equal('translate(-17, -74)')
- })
-
- it('Should only stack a part if needed', () => {
- let pattern = new Pattern()
- pattern.settings.mode = 'draft'
- let part = new pattern.Part()
- let short = part.shorthand()
- part.points.from = new short.Point(2, 2)
- part.points.to = new short.Point(19, 76)
- part.paths.test = new short.Path().move(part.points.from).line(part.points.to)
- part.home()
- expect(part.attributes.get('transform')).to.equal(false)
- part.home()
- expect(part.attributes.get('transform')).to.equal(false)
- })
- it('Should run hooks', () => {
- let count = 0
- const design = new Design()
- const pattern = new design({ paperless: true })
- const part = pattern.__createPartWithContext()
- part.hooks.preDraft = [
- {
- method: function () {
- count++
- },
- },
- ]
- part.runHooks('preDraft')
- expect(count).to.equal(1)
- })
-*/
-
it('Units closure should log a warning when passing a non-number', () => {
const part = {
name: 'test',
@@ -213,79 +173,169 @@ describe('Part', () => {
},
}
const design = new Design({ parts: [part] })
- const pattern = new design()
+ // Let's also cover the branch where complete is false
+ const pattern = new design({ complete: false} )
pattern.draft()
expect(pattern.stores[0].logs.warning.length).to.equal(1)
expect(pattern.stores[0].logs.warning[0]).to.equal(
'Calling `units(value)` but `value` is not a number (`string`)'
)
})
- /*
- describe('isEmpty', () => {
- it('Should return true if the part has no paths or snippets', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- expect(part.isEmpty()).to.be.true
- })
- it('Should return true if the part has paths but they have no length', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Path, paths } = part.shorthand()
- paths.seam = new Path()
- expect(part.isEmpty()).to.be.true
- })
-
- it("Should return true if the part has paths but they don't render", () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Path, paths, Point } = part.shorthand()
- paths.seam = new Path().move(new Point(0, 0)).line(new Point(2, 3)).setRender(false)
- expect(part.isEmpty()).to.be.true
- })
-
- it('Should return false if the part has a path with length', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Path, paths, Point } = part.shorthand()
- paths.seam = new Path().move(new Point(0, 0)).line(new Point(2, 3))
-
- expect(part.isEmpty()).to.be.false
- })
-
- it('Should return false if the part has a snippet', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Point, snippets, Snippet } = part.shorthand()
- snippets.test = new Snippet('test', new Point(0, 0))
-
- expect(part.isEmpty()).to.be.false
- })
-
- it('Should return false if the part has a point that has text', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Point, points } = part.shorthand()
- points.test = new Point(0, 0)
- points.test.attributes.set('data-text', 'text')
- expect(part.isEmpty()).to.be.false
- })
-
- it('Should return false if the part has a point that has a circle', () => {
- const design = new Design()
- const pattern = new design()
- const part = pattern.__createPartWithContext()
- const { Point, points } = part.shorthand()
- points.test = new Point(0, 0)
- points.test.attributes.set('data-circle', 10)
- expect(part.isEmpty()).to.be.false
- })
+ it('Should (un)hide a part with hide()/unhide()', () => {
+ const part = new Part()
+ expect(part.hidden).to.equal(false)
+ part.hide()
+ expect(part.hidden).to.equal(true)
+ part.unhide()
+ expect(part.hidden).to.equal(false)
+ })
+
+ it('Should (un)hide a part with setHidden()', () => {
+ const part = new Part()
+ expect(part.hidden).to.equal(false)
+ part.setHidden(true)
+ expect(part.hidden).to.equal(true)
+ part.setHidden(false)
+ expect(part.hidden).to.equal(false)
+ })
+
+ it('Draft method should receive the Snippet constructor', () => {
+ let method
+ const part = {
+ name: 'test',
+ draft: ({ Point, snippets, Snippet, part }) => {
+ method = Snippet
+ snippets.test = new Snippet('notch', new Point(19,80))
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(typeof method).to.equal('function')
+ expect(pattern.parts[0].test.snippets.test.def).to.equal('notch')
+ expect(pattern.parts[0].test.snippets.test.name).to.equal('test')
+ expect(pattern.parts[0].test.snippets.test.anchor.x).to.equal(19)
+ expect(pattern.parts[0].test.snippets.test.anchor.y).to.equal(80)
+ })
+
+ it('Measurments proxy should allow setting a measurement', () => {
+ const part = {
+ name: 'test',
+ draft: ({ measurements, part }) => {
+ measurements.head = 120
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.settings[0].measurements.head).to.equal(120)
+ })
+
+ it('Options proxy should allow setting an option', () => {
+ const part = {
+ name: 'test',
+ draft: ({ options, part }) => {
+ options.test = 120
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.settings[0].options.test).to.equal(120)
+ })
+
+ it('AbsoluteOptions proxy should allow setting an absoluteOption', () => {
+ const part = {
+ name: 'test',
+ draft: ({ absoluteOptions, part }) => {
+ absoluteOptions.test = 120
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.settings[0].absoluteOptions.test).to.equal(120)
+ })
+
+ it('Snapped percentage options should be available to the draft method', () => {
+ const part = {
+ name: 'test',
+ options: {
+ test: { pct: 10, min: 5, max: 25, snap: 5, ...pctBasedOn('head') }
+ },
+ draft: ({ paths, Path, Point, absoluteOptions, part }) => {
+ paths.test = new Path()
+ .move(new Point(0,0))
+ .line(new Point(absoluteOptions.test, 0))
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design({ measurements: { head: 200 } })
+ pattern.draft()
+ expect(pattern.parts[0].test.paths.test.ops[1].to.x).to.equal(20)
+ })
+
+ it('Accessing unknown option should log a warning', () => {
+ const part = {
+ name: 'test',
+ draft: ({ options, part }) => {
+ if (options.test || true) return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.stores[0].logs.warning.length).to.equal(1)
+ expect(pattern.stores[0].logs.warning[0]).to.equal('Tried to access `options.test` but it is `undefined`')
+ })
+
+ it('Accessing unknown absoluteOption should log a warning', () => {
+ const part = {
+ name: 'test',
+ draft: ({ absoluteOptions, part }) => {
+ if (absoluteOptions.test || true) return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.stores[0].logs.warning.length).to.equal(1)
+ expect(pattern.stores[0].logs.warning[0]).to.equal('Tried to access `absoluteOptions.test` but it is `undefined`')
+ })
+
+ it('Injecting a part should contain all data', () => {
+ const from = {
+ name: 'from',
+ draft: ({ points, Point, paths, Path, snippets, Snippet, part }) => {
+ points.from = new Point(0,0)
+ points.to = new Point(19,80)
+ points.start = new Point(100,100)
+ points.cp1 = new Point(100,200)
+ points.cp2 = new Point(200,100)
+ points.end = new Point(200,200)
+ paths.line = new Path().move(points.from).line(points.to)
+ paths.curve = new Path().move(points.start).curve(points.cp1, points.cp2, points.end)
+ snippets.test = new Snippet('notch', points.end)
+ return part
+ },
+ }
+ const to = {
+ from,
+ name: 'to',
+ draft: ({ part }) => part
+ }
+ const design = new Design({ parts: [from, to] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.parts[0].to.points.to.x).to.equal(19)
+ expect(pattern.parts[0].to.points.to.y).to.equal(80)
+ expect(typeof pattern.parts[0].to.paths.line).to.equal('object')
+ expect(pattern.parts[0].to.paths.curve.ops[1].cp2.x).to.equal(200)
})
- */
})
diff --git a/packages/core/tests/path.test.mjs b/packages/core/tests/path.test.mjs
index 64d6f967bac..a5ad05bf49d 100644
--- a/packages/core/tests/path.test.mjs
+++ b/packages/core/tests/path.test.mjs
@@ -57,6 +57,63 @@ describe('Path', () => {
expect(round(pattern.parts[0].test.paths.test.ops[2].cp1.y)).to.equal(10)
})
+ it('Should log a warning when passing a non-Point to smurve()', () => {
+ const part = {
+ name: 'test',
+ draft: ({ Point, points, Path, paths, part }) => {
+ points.from = new Point(10, 20)
+ points.cp1 = new Point(40, 10)
+ points.cp2 = new Point(60, 30)
+ points.to = new Point(90, 20)
+
+ paths.test = new Path()
+ .move(points.from)
+ .curve(points.cp1, points.cp2, points.to)
+ .smurve('hi', 'there')
+
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.stores[0].logs.warning.length).to.equal(2)
+ expect(pattern.stores[0].logs.warning[0]).to.equal('Called `Path.smurve(cp2, to)` but `to` is not a `Point` object')
+ })
+
+ it('Should log a warning when passing a non-Point to smurve_()', () => {
+ const part = {
+ name: 'test',
+ draft: ({ Point, Path, paths, part }) => {
+ paths.test = new Path().smurve_('hi')
+
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.stores[0].logs.warning.length).to.equal(1)
+ expect(pattern.stores[0].logs.warning[0]).to.equal('Called `Path.smurve_(to)` but `to` is not a `Point` object')
+ })
+
+ it('Should log a warning when passing a non-Path to the paths proxy', () => {
+ const part = {
+ name: 'test',
+ draft: ({ paths, part }) => {
+ paths.test = 'Wriing code can get very lonely sometimes'
+
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.stores[0].logs.warning.length).to.equal(2)
+ expect(pattern.stores[0].logs.warning[0]).to.equal('`paths.test` was set with a value that is not a `Path` object')
+ expect(pattern.stores[0].logs.warning[1]).to.equal('Could not set `name` property on `paths.test`')
+ })
+
it('Should offset a line', () => {
const part = {
name: 'test',
@@ -161,13 +218,30 @@ describe('Path', () => {
paths.curve = new Path()
.move(new Point(0, 0))
.curve(new Point(0, 50), new Point(100, 50), new Point(100, 0))
+ .close()
return part
},
}
const design = new Design({ parts: [part] })
const pattern = new design()
pattern.draft().render()
- expect(round(pattern.parts[0].test.paths.curve.roughLength())).to.equal(200)
+ expect(round(pattern.parts[0].test.paths.curve.roughLength())).to.equal(300)
+ })
+
+ it('Should return the rough length of a line', () => {
+ const part = {
+ name: 'test',
+ draft: ({ paths, Path, Point, part }) => {
+ paths.line = new Path()
+ .move(new Point(0, 0))
+ .line(new Point(0, 50))
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft().render()
+ expect(round(pattern.parts[0].test.paths.line.roughLength())).to.equal(50)
})
it('Should return the path start point', () => {
@@ -615,6 +689,32 @@ describe('Path', () => {
expect(round(line.to.y)).to.equal(46.98)
})
+ it('Should split a path on a line joint', () => {
+ const a = new Point(45, 60)
+ const b = new Point(10, 30)
+ const c = new Point(90, 30)
+ const test = new Path().move(a).line(b).line(c)
+
+ let halves = test.split(b)
+ expect(halves[0].ops[1].to.x).to.equal(10)
+ expect(halves[0].ops[1].to.y).to.equal(30)
+ expect(halves[1].ops[0].to.x).to.equal(10)
+ expect(halves[1].ops[0].to.y).to.equal(30)
+ })
+
+ it('Should split a path on a curve joint', () => {
+ const a = new Point(45, 60)
+ const b = new Point(10, 30)
+ const c = new Point(90, 30)
+ const test = new Path().move(a)._curve(b,b)._curve(c,c)
+
+ let halves = test.split(b)
+ expect(halves[0].ops[1].to.x).to.equal(10)
+ expect(halves[0].ops[1].to.y).to.equal(30)
+ expect(halves[1].ops[0].to.x).to.equal(10)
+ expect(halves[1].ops[0].to.y).to.equal(30)
+ })
+
it('Should trim a path when lines overlap', () => {
const A = new Point(0, 0)
const B = new Point(100, 100)
@@ -684,6 +784,16 @@ describe('Path', () => {
expect(test.ops[1].to.y).to.equal(20)
})
+ it('Calling translate with non-numbers should generate a warning', () => {
+ const log = []
+ const p = new Path()
+ p.log = { warning: msg => log.push(msg) }
+ p.translate('a', 'b')
+ expect(log.length).to.equal(2)
+ expect(log[0]).to.equal('Called `Path.translate(x, y)` but `x` is not a number')
+ expect(log[1]).to.equal('Called `Path.translate(x, y)` but `y` is not a number')
+ })
+
it('Should add a path attribute', () => {
const line = new Path()
.move(new Point(0, 0))
@@ -1039,7 +1149,7 @@ describe('Path', () => {
it('Should log a warning when splitting a path on a non-point', () => {
const part = {
name: 'test',
- draft: ({ Path, Point, points }) => {
+ draft: ({ Path, Point, points, part}) => {
points.a = new Path().move(new Point(0, 0)).line(new Point(0, 40)).split()
return part
},
@@ -1051,4 +1161,31 @@ describe('Path', () => {
'Called `Path.split(point)` but `point` is not a `Point` object'
)
})
+
+ it('Should add a class', () => {
+ const part = {
+ name: 'test',
+ draft: ({ Path, paths, Point, points, part }) => {
+ paths.line = new Path()
+ .move(new Point(0,0))
+ .line(new Point(10,10))
+ .addClass('fabric banana')
+ return part
+ },
+ }
+ const design = new Design({ parts: [part] })
+ const pattern = new design()
+ pattern.draft()
+ expect(pattern.parts[0].test.paths.line.attributes.get('class')).to.equal('fabric banana')
+ })
+
+ it('Should (un)hide a path with hide()/unhide()', () => {
+ const path = new Path()
+ expect(path.hidden).to.equal(false)
+ path.hide()
+ expect(path.hidden).to.equal(true)
+ path.unhide()
+ expect(path.hidden).to.equal(false)
+ })
+
})
diff --git a/packages/core/tests/pattern-draft.test.mjs b/packages/core/tests/pattern-draft.test.mjs
index 183c4806067..d7257a96acf 100644
--- a/packages/core/tests/pattern-draft.test.mjs
+++ b/packages/core/tests/pattern-draft.test.mjs
@@ -48,7 +48,7 @@ describe('Pattern', () => {
name: 'test.partB',
measurements: ['head', 'knee'],
optionalMeasurements: ['knee'],
- after: partA,
+ after: [ partA ],
plugins: [
{
name: 'testPlugin',
diff --git a/packages/core/tests/pattern-init.test.mjs b/packages/core/tests/pattern-init.test.mjs
index f64c8d7eae7..4da857b2497 100644
--- a/packages/core/tests/pattern-init.test.mjs
+++ b/packages/core/tests/pattern-init.test.mjs
@@ -580,6 +580,51 @@ describe('Pattern', () => {
expect(pattern.hooks.preRender.length).to.equal(1)
})
+ it('Load conditional plugins that are also passing data', () => {
+ const plugin1 = {
+ name: 'example1',
+ version: 1,
+ hooks: {
+ preRender: function (svg) {
+ svg.attributes.add('freesewing:plugin-example1', 1)
+ },
+ },
+ }
+ const plugin2 = {
+ name: 'example2',
+ version: 2,
+ hooks: {
+ preRender: function (svg) {
+ svg.attributes.add('freesewing:plugin-example2', 1)
+ },
+ },
+ }
+ const condition1 = () => true
+ const condition2 = () => false
+ const part1 = {
+ name: 'part1',
+ plugins: [
+ [plugin1, {} ],
+ { plugin: plugin2, condition: condition1 }
+ ],
+ draft: ({ part }) => part
+ }
+ const part2 = {
+ name: 'part2',
+ plugins: [
+ plugin2,
+ { plugin: plugin2, condition: condition2 },
+ ],
+ draft: ({ part }) => part
+ }
+ const design = new Design({
+ parts: [ part1, part2 ]
+ })
+ const pattern = new design()
+ pattern.init()
+ expect(pattern.hooks.preRender.length).to.equal(2)
+ })
+
it('Pattern.init() should register a hook via on', () => {
const Pattern = new Design()
const pattern = new Pattern()
diff --git a/packages/core/tests/svg.test.mjs b/packages/core/tests/svg.test.mjs
index 1423f2335c1..d44992df897 100644
--- a/packages/core/tests/svg.test.mjs
+++ b/packages/core/tests/svg.test.mjs
@@ -1,43 +1,45 @@
import chai from 'chai'
import chaiString from 'chai-string'
-//import { Design, Pattern } from '../src/index.mjs'
-//import pkg from '../package.json' assert { type: 'json' }
-//import render from './fixtures/render.mjs'
+import { Svg } from '../src/svg.mjs'
+import { Design, Pattern, Attributes } from '../src/index.mjs'
+import { version } from '../data.mjs'
+import render from './fixtures/render.mjs'
chai.use(chaiString)
const expect = chai.expect
-//const { version } = pkg
-it('FIXME: Write some tests here', () => {
- expect(true).to.equal(true)
-})
-
-/*
-describe('Svg', () => {
+const getPattern = (settings={}, draft=false) => {
const part = {
name: 'test',
- draft: part => {
- const { paths, Path, Point, points } = part.shorthand()
- points.a = new Path()
- .move(new Point(0, 0))
- .line(new Point(0, 40))
- .shiftFractionAlong()
- return part
- }
+ draft: draft
+ ? draft
+ : ({ paths, Path, Point, part }) => {
+ paths.test = new Path()
+ .move(new Point(0, 0))
+ .line(new Point(40, 20))
+ .curve(new Point(12, 34), new Point(56, 78), new Point(21, 32))
+ .close()
+ .attr('id', 'something')
+ .attr('class', 'freesewing')
+ return part
+ }
}
- const design = new Design({ parts: [ part ] })
- const pattern = new design()
+ const Pattern = new Design({ parts: [ part ] })
+
+ return new Pattern(settings)
+}
+
+const trim = svg => svg.split("\n").map(line => line.trim()).join('')
+
+describe('Svg', () => {
it('Svg constructor should initialize object', () => {
- pattern.render()
- let svg = pattern.svg
- expect(svg.openGroups).to.eql([])
+ const svg = new Svg()
+ expect(svg.attributes instanceof Attributes).to.equal(true)
expect(svg.freeId).to.equal(0)
expect(svg.body).to.equal('')
expect(svg.style).to.equal('')
- expect(svg.script).to.equal('')
expect(svg.defs).to.equal('')
- expect(svg.pattern).to.eql(pattern)
expect(svg.prefix).to.equal('')
expect(svg.attributes.get('xmlns')).to.equal('http://www.w3.org/2000/svg')
expect(svg.attributes.get('xmlns:svg')).to.equal('http://www.w3.org/2000/svg')
@@ -48,47 +50,233 @@ describe('Svg', () => {
expect(svg.attributes.get('freesewing')).to.equal(version)
})
- it('Should render Svg boilerplate', () => {
- let pattern = new Pattern()
- expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate)
+ it('Svg constructor should use the object we pass it as pattern', () => {
+ const obj = {}
+ const svg = new Svg(obj)
+ expect(svg.pattern).to.eql(obj)
})
- it('Should render language attribute', () => {
- let pattern = new Pattern()
- pattern.settings.locale = 'nl'
- expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplateNl)
+
+ it('Should render a pattern as SVG', () => {
+ const pattern = getPattern()
+ const svg = pattern.draft().render()
+ expect(trim(svg)).to.equalIgnoreSpaces(render.boilerplate)
})
- it('Should render Svg boilerplate for embedding', () => {
- let pattern = new Pattern()
- pattern.settings.embed = true
- expect(pattern.render()).to.equalIgnoreSpaces(render.embed)
+ it('Should render the SVG language attribute', () => {
+ const pattern = getPattern({ locale: 'nl' })
+ const svg = pattern.draft().render()
+ expect(svg).to.equalIgnoreSpaces(render.boilerplateNl)
})
- it('Should render Svg part boilerplate', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- expect(pattern.render()).to.equalIgnoreSpaces(render.part)
- pattern.parts.test.render = false
- expect(pattern.render()).to.equalIgnoreSpaces(render.boilerplate)
+ it('Should render the SVG viewBox attribute for embedding', () => {
+ const pattern = getPattern({ embed: true })
+ const svg = pattern.draft().render()
+ expect(trim(svg)).to.equalIgnoreSpaces(render.embed)
})
- it('Should render Svg path', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.paths.test = new p.Path()
- .move(new p.Point(0, 0))
- .line(new p.Point(40, 20))
- .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32))
- .close()
- .attr('id', 'something')
- .attr('class', 'freesewing')
- expect(pattern.render()).to.equalIgnoreSpaces(render.path)
+ it('Should render a stack as SVG', () => {
+ const pattern = getPattern()
+ pattern.draft().render()
+ const svg = pattern.svg.__renderStack(pattern.stacks.test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.part)
})
- it('Should not render Svg path when render property is false', () => {
+
+ it('Should render a part as SVG', () => {
+ const pattern = getPattern()
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.part)
+ })
+
+ it('Should render a path as SVG', () => {
+ const pattern = getPattern()
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPath(pattern.parts[0].test.paths.test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.path)
+ })
+
+ it('Should render Svg text', () => {
+ const pattern = getPattern({}, ({ points, Point, part }) => {
+ points.test = new Point(20, 20)
+ .attr('data-text', 'This is a test')
+ .attr('data-text-class', 'text-lg')
+ points.other = new Point(10, 10).attr('data-text', '')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.text)
+ })
+
+ it('Should render Svg multi-line text', () => {
+ const pattern = getPattern({}, ({ points, Point, part }) => {
+ points.test = new Point(20, 20)
+ .attr('data-text', 'This is a test\nwith text on\nmultiple lines')
+ .attr('data-text-class', 'text-lg')
+ .attr('data-text-lineheight', 8)
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.multiText)
+ })
+
+ it('Should render Svg multi-line text with default lineheight', () => {
+ const pattern = getPattern({}, ({ points, Point, part }) => {
+ points.test = new Point(20, 20)
+ .attr('data-text', 'This is a test\nwith text on\nmultiple lines')
+ .attr('data-text-class', 'text-lg')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.multiTextDflt)
+ })
+
+
+ it('Should render Svg text on path', () => {
+ const pattern = getPattern({}, ({ paths, Path, Point, part }) => {
+ paths.test = new Path()
+ .move(new Point(0, 0))
+ .line(new Point(40, 20))
+ .curve(new Point(12, 34), new Point(56, 78), new Point(21, 32))
+ .close()
+ .attr('data-text', 'This is another test')
+ .attr('data-text-class', 'text-sm')
+ .attr('class', 'freesewing')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPath)
+ })
+
+ it('Should render Svg text on path, center aligned', () => {
+ const pattern = getPattern({}, ({ paths, Path, Point, part }) => {
+ paths.test = new Path()
+ .attr('data-text', 'This is another test')
+ .attr('data-text-class', 'center')
+ .attr('class', 'freesewing')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPathCenter)
+ })
+
+ it('Should render Svg text on path, right aligned', () => {
+ const pattern = getPattern({}, ({ paths, Path, Point, part }) => {
+ paths.test = new Path()
+ .attr('data-text', 'This is another test')
+ .attr('data-text-class', 'right')
+ .attr('class', 'freesewing')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPathRight)
+ })
+
+ it('Should render an Svg circle', () => {
+ const pattern = getPattern({}, ({ points, Point, part }) => {
+ points.test = new Point(20, 20).attr('data-circle', '50')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.circle)
+ })
+
+ it('Should render an Svg snippet', () => {
+ const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
+ snippets.test = new Snippet('test', new Point(20, 20), 'This is a snippet')
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.snippet)
+ })
+
+ it('Should render a rotated Svg snippet', () => {
+ const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
+ snippets.test = new Snippet('test', new Point(20, 20), 'This is a snippet')
+ .attr( 'data-rotate', 90)
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.rotatedSnippet)
+ })
+
+ it('Should replaced double quotes in Svg text', () => {
+ const svg = new Svg()
+ expect(svg.__escapeText('This is a "test" message')).to.equal(
+ 'This is a “test“ message'
+ )
+ })
+
+ it('Should scale an Svg snippet', () => {
+ const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
+ snippets.test = new Snippet('test', new Point(20, 20), 'This is a snippet')
+ .attr( 'data-scale', 2)
+
+ return part
+ })
+ pattern.draft().render()
+ const svg = pattern.svg.__renderPart(pattern.parts[0].test)
+ expect(trim(svg)).to.equalIgnoreSpaces(render.scaledSnippet)
+ })
+
+ it('Should run preRender hook', () => {
+ const pattern = getPattern()
+ pattern.on('preRender', (svg) => {
+ svg.attributes.set('data-hook', 'preRender')
+ })
+ pattern.draft().render()
+ expect(pattern.svg.attributes.get('data-hook')).to.equal('preRender')
+ })
+
+ it('Should run insertText hook', () => {
+ const pattern = getPattern({}, ({ points, Point, part }) => {
+ points.test = new Point(20, 20)
+ .attr('data-text', 'This is a test')
+ .attr('data-text-class', 'text-lg')
+
+ return part
+ })
+ pattern.on('insertText', (locale, text) => {
+ return text.toUpperCase()
+ })
+ pattern.draft()
+ expect(pattern.render()).to.contain('THIS IS A TEST')
+ })
+
+ it('Should run postRender hook', () => {
+ const pattern = getPattern()
+ pattern.on('postRender', (svg) => {
+ svg.svg = 'test'
+ })
+ expect(pattern.render()).to.equal('test')
+ })
+
+ it('Should tab in and out', () => {
+ const svg = new Svg()
+ svg.tabs = 2
+ expect(svg.__tab()).to.equal(' ')
+ })
+
+ /*
+ it('Should not render an Svg path when render property is false', () => {
let pattern = new Pattern()
pattern.render()
pattern.parts.test = new pattern.Part()
@@ -103,185 +291,5 @@ describe('Svg', () => {
p.paths.test.render = false
expect(pattern.render()).to.equalIgnoreSpaces(render.part)
})
-
- it('Should render Svg text', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20)
- .attr('data-text', 'This is a test')
- .attr('data-text-class', 'text-lg')
- p.points.other = new p.Point(10, 10).attr('data-text', '')
- expect(pattern.render()).to.equalIgnoreSpaces(render.text)
- })
-
- it('Should render Svg multi-line text', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20)
- .attr('data-text', 'This is a test\nwith text on\nmultiple lines')
- .attr('data-text-class', 'text-lg')
- .attr('data-text-lineheight', 8)
- expect(pattern.render()).to.equalIgnoreSpaces(render.multiText)
- })
-
- it('Should render Svg multi-line text with default lineheight', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20)
- .attr('data-text', 'This is a test\nwith text on\nmultiple lines')
- .attr('data-text-class', 'text-lg')
- expect(pattern.render()).to.equalIgnoreSpaces(render.multiTextDflt)
- })
-
- it('Should not render text when there is none', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20)
- expect(pattern.render()).to.equalIgnoreSpaces(render.part)
- })
-
- it('Should render Svg text on path', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.paths.test = new p.Path()
- .move(new p.Point(0, 0))
- .line(new p.Point(40, 20))
- .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32))
- .close()
- .attr('data-text', 'This is another test')
- .attr('data-text-class', 'text-sm')
- .attr('class', 'freesewing')
- expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPath)
- })
-
- it('Should render Svg text on path, center aligned', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.paths.test = new p.Path()
- .move(new p.Point(0, 0))
- .line(new p.Point(40, 20))
- .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32))
- .close()
- .attr('data-text', 'This is another test')
- .attr('data-text-class', 'center')
- .attr('class', 'freesewing')
- expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathCenter)
- })
-
- it('Should render Svg text on path, right aligned', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.paths.test = new p.Path()
- .move(new p.Point(0, 0))
- .line(new p.Point(40, 20))
- .curve(new p.Point(12, 34), new p.Point(56, 78), new p.Point(21, 32))
- .close()
- .attr('data-text', 'This is another test')
- .attr('data-text-class', 'right')
- .attr('class', 'freesewing')
- expect(pattern.render()).to.equalIgnoreSpaces(render.textOnPathRight)
- })
-
- it('Should render an Svg circle', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20).attr('data-circle', '50')
- expect(pattern.render()).to.equalIgnoreSpaces(render.circle)
- })
-
- it('Should render an Svg snippet', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.snippets.test = new p.Snippet('test', new p.Point(20, 20), 'This is a snippet')
- expect(pattern.render()).to.equalIgnoreSpaces(render.snippet)
- })
-
- it('Should render a rotated Svg snippet', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.snippets.test = new p.Snippet('test', new p.Point(20, 20), 'This is a snippet').attr(
- 'data-rotate',
- 90
- )
- expect(pattern.render()).to.equalIgnoreSpaces(render.rotatedSnippet)
- })
-
- it('Should replaced double quotes in Svg text', () => {
- const pattern = new Pattern()
- pattern.render()
- expect(pattern.svg.escapeText('This is a "test" message')).to.equal(
- 'This is a “test“ message'
- )
- })
-
- it('Should scale an Svg snippet', () => {
- let pattern = new Pattern()
- pattern.render()
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.snippets.test = new p.Snippet('test', new p.Point(20, 20), 'This is a snippet').attr(
- 'data-scale',
- 2
- )
- expect(pattern.render()).to.contain('scale(2)')
- })
-
- it('Should run preRender hook', () => {
- let pattern = new Pattern()
- pattern.on('preRender', (svg) => {
- svg.attributes.set('data-hook', 'preRender')
- })
- pattern.render()
- expect(pattern.svg.attributes.get('data-hook')).to.equal('preRender')
- })
-
- it('Should run insertText hook', () => {
- let pattern = new Pattern()
- pattern.on('insertText', (locale, text) => {
- return text.toUpperCase()
- })
- pattern.parts.test = new pattern.Part()
- let p = pattern.parts.test
- p.points.test = new p.Point(20, 20)
- .attr('data-text', 'This is a test')
- .attr('data-text-class', 'text-lg')
- expect(pattern.render()).to.contain('THIS IS A TEST')
- })
-
- it('Should run postRender hook', () => {
- let pattern = new Pattern()
- pattern.on('postRender', (svg) => {
- svg.svg = 'test'
- })
- expect(pattern.render()).to.equal('test')
- })
-
- it('Should tab in and out', () => {
- let pattern = new Pattern()
- pattern.render()
- const svg = pattern.svg
- svg.tabs = 2
- expect(svg.tab()).to.equal(' ')
- })
-})
*/
+})
diff --git a/packages/core/tests/utils.test.mjs b/packages/core/tests/utils.test.mjs
index a80ce914b1a..e1a4a3c4828 100644
--- a/packages/core/tests/utils.test.mjs
+++ b/packages/core/tests/utils.test.mjs
@@ -1,6 +1,7 @@
import chai from 'chai'
import {
Point,
+ Design,
capitalize,
beamsIntersect,
linesIntersect,
@@ -23,6 +24,7 @@ import {
deg2rad,
rad2deg,
pctBasedOn,
+ generateStackTransform,
} from '../src/index.mjs'
const { expect } = chai
@@ -474,29 +476,20 @@ describe('Utils', () => {
expect(result.toAbs(0.0123, { measurements })).to.equal(12.3)
expect(result.fromAbs(12.3, { measurements })).to.equal(0.0123)
})
- /*
- it('Should generate a part transform', () => {
- const part = {
+ it('Should generate a stack transform', () => {
+ const test = {
name: 'test',
- draft: part => {
- const { points, Point, paths, Path } = part.shorthand()
+ draft: ({ points, Point, paths, Path, part }) => {
points.from = new Point(2, 2)
points.to = new Point(19, 76)
paths.test = new Path().move(points.from).line(points.to)
return part
}
}
- const design = new Design({ parts: [ part ]})
+ const design = new Design({ parts: [ test ]})
const pattern = new design()
- pattern.draft().render()
- const transform = generatePartTransform(30, 60, 90, true, true, pattern.__parts.test)
- expect(transform.transform).to.equal(
- `translate(${30 + part.topLeft.x + part.bottomRight.x} ${
- 60 + part.topLeft.y + part.bottomRight.y
- }) scale(-1 -1) rotate(90 ${part.topLeft.x + part.width / 2} ${
- part.topLeft.y + part.height / 2
- })`
- )
+ const props = pattern.draft().getRenderProps()
+ const transform = generateStackTransform(30, 60, 90, true, true, props.stacks.test)
+ expect(transform.transform).to.equal('translate(51 138) scale(-1 -1) rotate(90 10.5 39)')
})
- */
})