Merge branch 'develop' into octoplushie
This commit is contained in:
commit
3ac64f9458
9 changed files with 252 additions and 59 deletions
|
@ -18,7 +18,7 @@ function Part() {
|
||||||
this.render = true
|
this.render = true
|
||||||
this.utils = utils
|
this.utils = utils
|
||||||
this.layout = { move: { x: 0, y: 0 } }
|
this.layout = { move: { x: 0, y: 0 } }
|
||||||
|
this.cut = { grain: 90, materials: {} }
|
||||||
this.Point = Point
|
this.Point = Point
|
||||||
this.Path = Path
|
this.Path = Path
|
||||||
this.Snippet = Snippet
|
this.Snippet = Snippet
|
||||||
|
@ -194,6 +194,8 @@ Part.prototype.shorthand = function () {
|
||||||
paperless,
|
paperless,
|
||||||
events: this.context.events,
|
events: this.context.events,
|
||||||
raise: this.context.raise,
|
raise: this.context.raise,
|
||||||
|
addCut: this.addCut,
|
||||||
|
removeCut: this.removeCut,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.context.settings.debug) {
|
if (this.context.settings.debug) {
|
||||||
|
@ -357,20 +359,61 @@ Part.prototype.generateTransform = function(transforms) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Chainable way to set the grain property */
|
/** Chainable way to add the cut info */
|
||||||
Part.prototype.setGrain = function (grain = 90) {
|
Part.prototype.addCut = function (cut=2, material='fabric', identical=false) {
|
||||||
this.attributes.set('data-grain', grain)
|
if (cut === false) {
|
||||||
|
if (this.cut.materials[material]) delete this.cut.materials[material]
|
||||||
|
else this.context.raise.warning(`Tried to remove a material that is not set`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (typeof this.cut.materials[material] === 'undefined') this.cut.materials[material] = {}
|
||||||
|
if (!(Number.isInteger(cut) && cut > -1)) {
|
||||||
|
this.context.raise.error(`Tried to set cut to a value that is not a positive integer`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (typeof material !== 'string') {
|
||||||
|
this.context.raise.warning(`Tried to set material to a value that is not a string`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
this.cut.materials[material].cut = cut
|
||||||
|
this.cut.materials[material].identical = identical
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Chainable way to set the grain property */
|
/** Chainable way to remove (some) cut info */
|
||||||
Part.prototype.setCut = function (cut = { count: 2, mirror: true, onFold: false }) {
|
Part.prototype.removeCut = function (material=false) {
|
||||||
this.attributes.set('data-cut', cut)
|
return this.addCut(false, material)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Chainable way to add the grain info */
|
||||||
|
Part.prototype.setGrain = function (grain=false) {
|
||||||
|
if (grain === false) {
|
||||||
|
this.cut.grain = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (typeof grain !== 'number') {
|
||||||
|
this.context.raise.error('Called part.setGrain() with a value that is not a number')
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
this.cut.grain = grain
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Chainable way to add the cutOnFold info */
|
||||||
|
Part.prototype.setCutOnFold = function (p1, p2) {
|
||||||
|
if (p1 === false && typeof p2 === 'undefined') {
|
||||||
|
delete this.cut.cutOnFold
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (p1 instanceof Point && p2 instanceof Point) {
|
||||||
|
this.cut.cutOnFold = [p1, p2]
|
||||||
|
}
|
||||||
|
else this.context.raise.error('Called part.setCutOnFold() but at least one parameter is not a Point instance')
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default Part
|
export default Part
|
||||||
|
|
|
@ -59,6 +59,7 @@ export default function Pattern(config = { options: {} }) {
|
||||||
this.height = 0 // Will be set after render
|
this.height = 0 // Will be set after render
|
||||||
this.is = '' // Will be set when drafting/sampling
|
this.is = '' // Will be set when drafting/sampling
|
||||||
this.autoLayout = { parts: {} } // Will hold auto-generated layout
|
this.autoLayout = { parts: {} } // Will hold auto-generated layout
|
||||||
|
this.cutList = {} // Will hold the cutlist
|
||||||
|
|
||||||
this.store = new Store(this.raise) // Store for sharing data across parts
|
this.store = new Store(this.raise) // Store for sharing data across parts
|
||||||
this.parts = {} // Parts container
|
this.parts = {} // Parts container
|
||||||
|
@ -191,6 +192,7 @@ Pattern.prototype.runHooks = function (hookName, data = false) {
|
||||||
Pattern.prototype.draft = function () {
|
Pattern.prototype.draft = function () {
|
||||||
if (this.is !== 'sample') {
|
if (this.is !== 'sample') {
|
||||||
this.is = 'draft'
|
this.is = 'draft'
|
||||||
|
this.cutList = {}
|
||||||
this.raise.debug(`Drafting pattern`)
|
this.raise.debug(`Drafting pattern`)
|
||||||
}
|
}
|
||||||
// Handle snap for pct options
|
// Handle snap for pct options
|
||||||
|
@ -229,6 +231,7 @@ Pattern.prototype.draft = function () {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.parts[partName] = this[method](this.parts[partName])
|
this.parts[partName] = this[method](this.parts[partName])
|
||||||
|
if (this.parts[partName].render ) this.cutList[partName] = this.parts[partName].cut
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.raise.error([`Unable to draft part \`${partName}\``, err])
|
this.raise.error([`Unable to draft part \`${partName}\``, err])
|
||||||
}
|
}
|
||||||
|
@ -669,6 +672,13 @@ Pattern.prototype.wants = function (partName) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cutList property
|
||||||
|
*/
|
||||||
|
Pattern.prototype.getCutList = function () {
|
||||||
|
return this.cutList
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns props required to render this pattern through
|
/** Returns props required to render this pattern through
|
||||||
* an external renderer (eg. a React component)
|
* an external renderer (eg. a React component)
|
||||||
*/
|
*/
|
||||||
|
@ -692,6 +702,7 @@ Pattern.prototype.getRenderProps = function () {
|
||||||
warning: this.events.warning,
|
warning: this.events.warning,
|
||||||
error: this.events.error,
|
error: this.events.error,
|
||||||
}
|
}
|
||||||
|
props.cutList = this.cutList
|
||||||
props.parts = {}
|
props.parts = {}
|
||||||
for (let p in this.parts) {
|
for (let p in this.parts) {
|
||||||
if (this.parts[p].render) {
|
if (this.parts[p].render) {
|
||||||
|
|
|
@ -273,33 +273,129 @@ it("Should generate the part transforms", () => {
|
||||||
expect(part.attributes.list['transform-origin'][0]).to.equal('10.5 39')
|
expect(part.attributes.list['transform-origin'][0]).to.equal('10.5 39')
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should set the part grain", () => {
|
|
||||||
|
it("Should add the part cut", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
expect(part.cut.materials.fabric.cut).to.equal(4)
|
||||||
|
expect(part.cut.materials.fabric.identical).to.equal(true)
|
||||||
|
part.addCut()
|
||||||
|
expect(part.cut.materials.fabric.cut).to.equal(2)
|
||||||
|
expect(part.cut.materials.fabric.identical).to.equal(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate an error if cut is not a number", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut('a', 'fabric', true)
|
||||||
|
expect(pattern.events.error.length).to.equal(1)
|
||||||
|
expect(pattern.events.error[0]).to.equal('Tried to set cut to a value that is not a positive integer')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate an warning if material is not a string", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(3, 4)
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to set material to a value that is not a string')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate an error when removing a material that is not set (through addCut)", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.addCut(false, 'lining')
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should remove the part cut through addCut", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.addCut(false, 'fabric')
|
||||||
|
expect(typeof part.cut.materials.fabric).to.equal('undefined')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should remove the part cut through removeCut", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.removeCut('fabric')
|
||||||
|
expect(typeof part.cut.materials.fabric).to.equal('undefined')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate an error when removing a material that is not set (through removeCut)", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.removeCut('lining')
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate an error when removing a material that is not a string (through removeCut)", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.removeCut(23)
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should generate a warning when calling removeCut without parameters", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
part.addCut(4, 'fabric', true)
|
||||||
|
part.removeCut()
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to remove a material that is not set')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should set the part grainline", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
expect(part.cut.grain).to.equal(90)
|
||||||
|
part.setGrain(123)
|
||||||
|
expect(part.cut.grain).to.equal(123)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should raise a warning when calling part.setGrain() without any parameters", () => {
|
||||||
let pattern = new freesewing.Pattern();
|
let pattern = new freesewing.Pattern();
|
||||||
pattern.settings.mode = "draft";
|
|
||||||
let part = new pattern.Part();
|
let part = new pattern.Part();
|
||||||
part.setGrain(666)
|
|
||||||
expect(part.attributes.list['data-grain'][0]).to.equal(666)
|
|
||||||
part.setGrain()
|
part.setGrain()
|
||||||
expect(part.attributes.list['data-grain'][0]).to.equal(90)
|
expect(part.cut.grain).to.equal(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should set the part cut", () => {
|
it("Should raise an error when calling part.setGrain() with a value that is not a number", () => {
|
||||||
let pattern = new freesewing.Pattern();
|
let pattern = new freesewing.Pattern();
|
||||||
pattern.settings.mode = "draft";
|
|
||||||
let part = new pattern.Part();
|
let part = new pattern.Part();
|
||||||
const cut = {
|
part.setGrain('a')
|
||||||
count: 4,
|
expect(part.cut.grain).to.equal(90)
|
||||||
mirror: false,
|
expect(pattern.events.error.length).to.equal(1)
|
||||||
onFold: true
|
expect(pattern.events.error[0]).to.equal('Called part.setGrain() with a value that is not a number')
|
||||||
}
|
});
|
||||||
const dflt = {
|
|
||||||
count: 2,
|
it("Should set and then remove the cutOnFold", () => {
|
||||||
mirror: true,
|
let pattern = new freesewing.Pattern();
|
||||||
onFold: false
|
let part = new pattern.Part();
|
||||||
}
|
const { Point } = part.shorthand()
|
||||||
part.setCut(cut)
|
part.setCutOnFold(new Point(2,3), new Point(100,200))
|
||||||
expect(JSON.stringify(part.attributes.list['data-cut'][0])).to.equal(JSON.stringify(cut))
|
expect(part.cut.cutOnFold[0].x).to.equal(2)
|
||||||
part.setCut()
|
expect(part.cut.cutOnFold[0].y).to.equal(3)
|
||||||
expect(JSON.stringify(part.attributes.list['data-cut'][0])).to.equal(JSON.stringify(dflt))
|
expect(part.cut.cutOnFold[1].x).to.equal(100)
|
||||||
|
expect(part.cut.cutOnFold[1].y).to.equal(200)
|
||||||
|
part.setCutOnFold(false)
|
||||||
|
expect(typeof part.cut.cutOnFold).to.equal('undefined')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should raise an error when setting the cutOnFold with a non-Point value", () => {
|
||||||
|
let pattern = new freesewing.Pattern();
|
||||||
|
let part = new pattern.Part();
|
||||||
|
const { Point } = part.shorthand()
|
||||||
|
part.setCutOnFold(new Point(2,3), 12)
|
||||||
|
expect(pattern.events.error.length).to.equal(1)
|
||||||
|
expect(pattern.events.error[0]).to.equal('Called part.setCutOnFold() but at least one parameter is not a Point instance')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -712,3 +712,21 @@ it("Should handle a list snapped option", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("Should retrieve the cutList", () => {
|
||||||
|
const Test = new freesewing.Design({
|
||||||
|
name: "test",
|
||||||
|
parts: ['front'],
|
||||||
|
})
|
||||||
|
Test.prototype.draftFront = function(part) {
|
||||||
|
part.addCut(4, 'lining', true)
|
||||||
|
|
||||||
|
return part
|
||||||
|
};
|
||||||
|
const pattern = new Test()
|
||||||
|
expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({}))
|
||||||
|
pattern.draft()
|
||||||
|
console.log(pattern.parts.front.cut)
|
||||||
|
const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}`
|
||||||
|
expect(JSON.stringify(pattern.getCutList())).to.equal(list)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,3 +26,4 @@ it("Should set an attribute", () => {
|
||||||
s.attr("class", "less", true);
|
s.attr("class", "less", true);
|
||||||
expect(s.attributes.get("class")).to.equal("less");
|
expect(s.attributes.get("class")).to.equal("less");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,10 @@ it("Should set a store value only if unset", () => {
|
||||||
store.setIfUnset("few", "schmoo");
|
store.setIfUnset("few", "schmoo");
|
||||||
expect(store.get("few")).to.equal("baz");
|
expect(store.get("few")).to.equal("baz");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should raise a warning when retrieving a invalid key", () => {
|
||||||
|
store.get('nope')
|
||||||
|
expect(pattern.events.warning.length).to.equal(1)
|
||||||
|
expect(pattern.events.warning[0]).to.equal('Tried to access `nope` in the `store` but it is not set')
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -267,4 +267,12 @@ it("Should run postRender hook", () => {
|
||||||
expect(pattern.render()).to.equal("test");
|
expect(pattern.render()).to.equal("test");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should tab in and out", () => {
|
||||||
|
let pattern = new freesewing.Pattern()
|
||||||
|
pattern.render()
|
||||||
|
const svg = pattern.svg
|
||||||
|
svg.tabs = 2
|
||||||
|
expect(svg.tab()).to.equal(' ')
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,21 +14,25 @@ export default {
|
||||||
},
|
},
|
||||||
macros: {
|
macros: {
|
||||||
cutonfold: function (so) {
|
cutonfold: function (so) {
|
||||||
|
const { points, complete } = this.shorthand()
|
||||||
if (so === false) {
|
if (so === false) {
|
||||||
delete this.points.cutonfoldFrom
|
delete this.points.cutonfoldFrom
|
||||||
delete this.points.cutonfoldTo
|
delete this.points.cutonfoldTo
|
||||||
delete this.points.cutonfoldVia1
|
delete this.points.cutonfoldVia1
|
||||||
delete this.points.cutonfoldVia2
|
delete this.points.cutonfoldVia2
|
||||||
delete this.paths.cutonfold
|
delete this.paths.cutonfold
|
||||||
|
this.setCutOnFold(false) // Restore default
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const points = this.points
|
|
||||||
so = {
|
so = {
|
||||||
offset: 15,
|
offset: 15,
|
||||||
margin: 5,
|
margin: 5,
|
||||||
prefix: '',
|
prefix: '',
|
||||||
...so,
|
...so,
|
||||||
}
|
}
|
||||||
|
this.setCutOnFold(so.from, so.to)
|
||||||
|
if (so.grainline) this.setGrain(so.from.angle(so.to))
|
||||||
|
if (complete) {
|
||||||
points['cutonfoldFrom' + so.prefix] = so.from.shiftFractionTowards(so.to, so.margin / 100)
|
points['cutonfoldFrom' + so.prefix] = so.from.shiftFractionTowards(so.to, so.margin / 100)
|
||||||
points['cutonfoldTo' + so.prefix] = so.to.shiftFractionTowards(so.from, so.margin / 100)
|
points['cutonfoldTo' + so.prefix] = so.to.shiftFractionTowards(so.from, so.margin / 100)
|
||||||
points['cutonfoldVia1' + so.prefix] = points['cutonfoldFrom' + so.prefix]
|
points['cutonfoldVia1' + so.prefix] = points['cutonfoldFrom' + so.prefix]
|
||||||
|
@ -48,6 +52,7 @@ export default {
|
||||||
.attr('marker-end', 'url(#cutonfoldTo)')
|
.attr('marker-end', 'url(#cutonfoldTo)')
|
||||||
.attr('data-text', text)
|
.attr('data-text', text)
|
||||||
.attr('data-text-class', 'center fill-note')
|
.attr('data-text-class', 'center fill-note')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,16 @@ export default {
|
||||||
delete this.points.grainlineFrom
|
delete this.points.grainlineFrom
|
||||||
delete this.points.grainlineTo
|
delete this.points.grainlineTo
|
||||||
delete this.paths.grainline
|
delete this.paths.grainline
|
||||||
|
this.setGrain(90) // Restoring default
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
so = {
|
so = {
|
||||||
...dflts,
|
...dflts,
|
||||||
...so,
|
...so,
|
||||||
}
|
}
|
||||||
let points = this.points
|
const { points, complete } = this.shorthand()
|
||||||
|
this.setGrain(so.from.angle(so.to))
|
||||||
|
if (complete) {
|
||||||
points.grainlineFrom = so.from.shiftFractionTowards(so.to, 0.05)
|
points.grainlineFrom = so.from.shiftFractionTowards(so.to, 0.05)
|
||||||
points.grainlineTo = so.to.shiftFractionTowards(so.from, 0.05)
|
points.grainlineTo = so.to.shiftFractionTowards(so.from, 0.05)
|
||||||
this.paths.grainline = new this.Path()
|
this.paths.grainline = new this.Path()
|
||||||
|
@ -39,6 +42,7 @@ export default {
|
||||||
.attr('marker-end', 'url(#grainlineTo)')
|
.attr('marker-end', 'url(#grainlineTo)')
|
||||||
.attr('data-text', so.text)
|
.attr('data-text', so.text)
|
||||||
.attr('data-text-class', 'center fill-note')
|
.attr('data-text-class', 'center fill-note')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue