wip: Allow runtime adding of parts
Just call `pattern.addPart()` and pass it either: - a part object with all it entails - a draft method as first and name as second parameter This will overwrite any existing parts without any warning
This commit is contained in:
parent
2eee247676
commit
689f908f68
4 changed files with 111 additions and 56 deletions
|
@ -1,51 +1,5 @@
|
|||
import Pattern from './pattern'
|
||||
|
||||
// Add part-level options
|
||||
const addOptions = (part, config) => {
|
||||
if (part.options) {
|
||||
for (const optionName in part.options) {
|
||||
config.options[optionName] = part.options[optionName]
|
||||
}
|
||||
}
|
||||
if (part.from) addOptions(part.from, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Add part-level measurements
|
||||
const addMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.measurements
|
||||
? [...config.measurements]
|
||||
: []
|
||||
if (part.measurements) {
|
||||
for (const m of part.measurements) list.push(m)
|
||||
}
|
||||
if (part.from) addMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.measurements = [...new Set(list)]
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Add part-level optional measurements
|
||||
const addOptionalMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.optionalMeasurements
|
||||
? [...config.optionalMeasurements]
|
||||
: []
|
||||
if (part.optionalMeasurements) {
|
||||
for (const m of part.optionalMeasurements) {
|
||||
// Don't add it's a required measurement for another part
|
||||
if (config.measurements.indexOf(m) === -1) list.push(m)
|
||||
}
|
||||
}
|
||||
if (part.from) addOptionalMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.optionalMeasurements = [...new Set(list)]
|
||||
|
||||
return config
|
||||
}
|
||||
import { addOptions, addMeasurements, addOptionalMeasurements } from './utils.js'
|
||||
|
||||
/*
|
||||
* The Design constructor. Returns a Pattern constructor
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
import { macroName, sampleStyle, capitalize, decoratePartDependency } from './utils'
|
||||
import {
|
||||
macroName,
|
||||
sampleStyle,
|
||||
capitalize,
|
||||
decoratePartDependency,
|
||||
addOptions,
|
||||
addMeasurements,
|
||||
addOptionalMeasurements
|
||||
} from './utils.js'
|
||||
import Part from './part'
|
||||
import Point from './point'
|
||||
import Path from './path'
|
||||
|
@ -243,10 +251,17 @@ Pattern.prototype.runHooks = function (hookName, data = false) {
|
|||
/*
|
||||
* Allows adding a part at run-time
|
||||
*/
|
||||
Pattern.prototype.addPart = function (part, name=false, key) {
|
||||
if (!part.draft) part = decoratePartDependency(part, givenName)
|
||||
Pattern.prototype.addPart = function (part, name=false) {
|
||||
if (!part.draft) part = decoratePartDependency(part, name)
|
||||
if (typeof part?.draft === 'function') {
|
||||
this.__parts[part.name] = part
|
||||
if (part.name) {
|
||||
this.config.parts[part.name] = part
|
||||
// Add part options/measurements/optionalMeasurements to config
|
||||
this.config = addOptions(part, this.config)
|
||||
this.config = addMeasurements(part, this.config)
|
||||
this.config = addOptionalMeasurements(part, this.config)
|
||||
}
|
||||
else this.raise.error(`Part must have a name`)
|
||||
}
|
||||
else this.raise.warning(`Cannot attach part ${name} because it is not a part`)
|
||||
|
||||
|
|
|
@ -388,3 +388,52 @@ export const generatePartTransform = (x, y, rotate, flipX, flipY, part) => {
|
|||
* Makes sure an object passed to be attached as a part it not merely a method
|
||||
*/
|
||||
export const decoratePartDependency = (obj, name) => (typeof obj === 'function') ? { draft: obj, name } : obj
|
||||
|
||||
// Add part-level options
|
||||
export const addOptions = (part, config) => {
|
||||
if (part.options) {
|
||||
for (const optionName in part.options) {
|
||||
config.options[optionName] = part.options[optionName]
|
||||
}
|
||||
}
|
||||
if (part.from) addOptions(part.from, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Add part-level measurements
|
||||
export const addMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.measurements
|
||||
? [...config.measurements]
|
||||
: []
|
||||
if (part.measurements) {
|
||||
for (const m of part.measurements) list.push(m)
|
||||
}
|
||||
if (part.from) addMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.measurements = [...new Set(list)]
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Add part-level optional measurements
|
||||
export const addOptionalMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.optionalMeasurements
|
||||
? [...config.optionalMeasurements]
|
||||
: []
|
||||
if (part.optionalMeasurements) {
|
||||
for (const m of part.optionalMeasurements) {
|
||||
// Don't add it's a required measurement for another part
|
||||
if (config.measurements.indexOf(m) === -1) list.push(m)
|
||||
}
|
||||
}
|
||||
if (part.from) addOptionalMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.optionalMeasurements = [...new Set(list)]
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -723,6 +723,8 @@ it("Should retrieve the cutList", () => {
|
|||
});
|
||||
|
||||
// 2022 style part inheritance
|
||||
// I am aware this does too much for one unit test, but this is to simplify TDD
|
||||
// we can split it up later
|
||||
it("Design constructor should resolve nested dependencies (2022)", () => {
|
||||
const partA = {
|
||||
name: "partA",
|
||||
|
@ -765,19 +767,35 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
return part
|
||||
}
|
||||
}
|
||||
const partR = { // R for runtime, which is when this wil be attached
|
||||
name: "partR",
|
||||
from: partA,
|
||||
options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } },
|
||||
measurements: [ 'measieR' ],
|
||||
optionalMeasurements: [ 'optmeasieR', 'measieA' ],
|
||||
draft: part => {
|
||||
const { points, Point, paths, Path } = part.shorthand()
|
||||
points.r1 = new Point(4,4)
|
||||
points.r2 = new Point(44,44)
|
||||
paths.r = new Path().move(points.r1).line(points.r2)
|
||||
return part
|
||||
}
|
||||
}
|
||||
|
||||
const design = new freesewing.Design({ parts: { partC } });
|
||||
const pattern = new design().draft()
|
||||
const Design = new freesewing.Design({ parts: { partC } });
|
||||
const pattern = new Design().addPart(partR).draft()
|
||||
// Measurements
|
||||
expect(pattern.config.measurements.length).to.equal(3)
|
||||
expect(pattern.config.measurements.length).to.equal(4)
|
||||
expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieR') === -1).to.equal(false)
|
||||
// Optional measurements
|
||||
expect(pattern.config.optionalMeasurements.length).to.equal(3)
|
||||
expect(pattern.config.optionalMeasurements.length).to.equal(4)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieR') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true)
|
||||
// Options
|
||||
expect(pattern.config.options.optionA.bool).to.equal(true)
|
||||
|
@ -787,17 +805,23 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
expect(pattern.config.options.optionC.deg).to.equal(5)
|
||||
expect(pattern.config.options.optionC.min).to.equal(0)
|
||||
expect(pattern.config.options.optionC.max).to.equal(15)
|
||||
expect(pattern.config.options.optionR.dflt).to.equal('red')
|
||||
expect(pattern.config.options.optionR.list[0]).to.equal('red')
|
||||
expect(pattern.config.options.optionR.list[1]).to.equal('green')
|
||||
expect(pattern.config.options.optionR.list[2]).to.equal('blue')
|
||||
// Dependencies
|
||||
expect(pattern.config.dependencies.partB[0]).to.equal('partA')
|
||||
expect(pattern.config.dependencies.partC[0]).to.equal('partB')
|
||||
expect(pattern.config.dependencies.partR[0]).to.equal('partA')
|
||||
// Inject
|
||||
expect(pattern.config.inject.partB).to.equal('partA')
|
||||
expect(pattern.config.inject.partC).to.equal('partB')
|
||||
expect(pattern.config.inject.partR).to.equal('partA')
|
||||
// Draft order
|
||||
expect(pattern.config.draftOrder[0]).to.equal('partA')
|
||||
expect(pattern.config.draftOrder[1]).to.equal('partB')
|
||||
expect(pattern.config.draftOrder[2]).to.equal('partC')
|
||||
expect(pattern.config.draftOrder[2]).to.equal('partC')
|
||||
expect(pattern.config.draftOrder[3]).to.equal('partR')
|
||||
// Points
|
||||
expect(pattern.parts.partA.points.a1.x).to.equal(1)
|
||||
expect(pattern.parts.partA.points.a1.y).to.equal(1)
|
||||
|
@ -811,6 +835,10 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
expect(pattern.parts.partC.points.c1.y).to.equal(3)
|
||||
expect(pattern.parts.partC.points.c2.x).to.equal(33)
|
||||
expect(pattern.parts.partC.points.c2.y).to.equal(33)
|
||||
expect(pattern.parts.partR.points.r1.x).to.equal(4)
|
||||
expect(pattern.parts.partR.points.r1.y).to.equal(4)
|
||||
expect(pattern.parts.partR.points.r2.x).to.equal(44)
|
||||
expect(pattern.parts.partR.points.r2.y).to.equal(44)
|
||||
// Paths in partA
|
||||
expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1)
|
||||
expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1)
|
||||
|
@ -838,4 +866,13 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3)
|
||||
expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33)
|
||||
expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33)
|
||||
// Paths in partR
|
||||
expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1)
|
||||
expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1)
|
||||
expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11)
|
||||
expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11)
|
||||
expect(pattern.parts.partR.paths.r.ops[0].to.x).to.equal(4)
|
||||
expect(pattern.parts.partR.paths.r.ops[0].to.y).to.equal(4)
|
||||
expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44)
|
||||
expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44)
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue