UNPKG

@freesewing/core

Version:

A library for creating made-to-measure sewing patterns

162 lines (134 loc) 5.12 kB
import { Attributes } from './attributes.mjs' import { Point } from './point.mjs' import * as utils from './utils.mjs' export function Stack(name = null) { // Non-enumerable properties utils.__addNonEnumProp(this, 'freeId', 0) utils.__addNonEnumProp(this, 'layout', { move: { x: 0, y: 0 } }) // Enumerable properties this.attributes = new Attributes() this.parts = new Set() this.name = name this.topLeft = false this.bottomRight = false this.width = false this.height = false this.anchor = new Point(0, 0) return this } /* Adds a part to the stack */ Stack.prototype.addPart = function (part) { if (part) this.parts.add(part) return this } /* Returns a stack object suitbale for renderprops */ Stack.prototype.asRenderProps = function () { return { name: this.name, attributes: this.attributes.asRenderProps(), topLeft: this.topLeft, bottomRight: this.bottomRight, width: this.width, height: this.height, parts: [...this.parts].map((part) => part.asRenderProps()), } } /* Returns a list of parts in this stack */ Stack.prototype.getPartList = function () { return [...this.parts] } /* Returns a list of names of parts in this stack */ Stack.prototype.getPartNames = function () { return [...this.parts].map((p) => p.name) } /** Calculates the stack's bounding box and sets it */ Stack.prototype.home = function () { if (this.topLeft) return this // Cached this.topLeft = new Point(Infinity, Infinity) this.bottomRight = new Point(-Infinity, -Infinity) for (const part of this.getPartList()) { part.__boundary() const { topLeft, bottomRight } = utils.getTransformedBounds( part, part.attributes.getAsArray('transform') ) if (!topLeft) { continue } // get the top left, the minimum x and y values of any corner this.topLeft.x = Math.min(this.topLeft.x, topLeft.x) this.topLeft.y = Math.min(this.topLeft.y, topLeft.y) // get the bottom right, the maximum x and y values of any corner this.bottomRight.x = Math.max(this.bottomRight.x, bottomRight.x) this.bottomRight.y = Math.max(this.bottomRight.y, bottomRight.y) } // Fix infinity if it's not overwritten if (this.topLeft.x === Infinity) this.topLeft.x = 0 if (this.topLeft.y === Infinity) this.topLeft.y = 0 if (this.bottomRight.x === -Infinity) this.bottomRight.x = 0 if (this.bottomRight.y === -Infinity) this.bottomRight.y = 0 // Add margin let margin = 0 for (const set in this.context.settings) { if (this.context.settings[set].margin > margin) margin = this.context.settings[set].margin if (this.context.settings[set].paperless && margin < 10) margin = 10 } this.topLeft.x -= margin this.topLeft.y -= margin this.bottomRight.x += margin this.bottomRight.y += margin // Set dimensions this.width = this.bottomRight.x - this.topLeft.x this.height = this.bottomRight.y - this.topLeft.y this.width = this.bottomRight.x - this.topLeft.x this.height = this.bottomRight.y - this.topLeft.y // Add transform //this.anchor = this.getAnchor() // FIXME: Can we be certain this is always (0,0) / this.anchor = new Point(0, 0) if (this.topLeft.x === this.anchor.x && this.topLeft.y === this.anchor.y) return this else { this.attr( 'transform', `translate(${this.anchor.x - this.topLeft.x}, ${this.anchor.y - this.topLeft.y})` ) this.layout.move.x = this.anchor.x - this.topLeft.x this.layout.move.y = this.anchor.y - this.topLeft.y } return this } /** Finds the anchor to align parts in this stack */ Stack.prototype.getAnchor = function () { let anchorPoint = true let gridAnchorPoint = true const parts = this.getPartList() for (const part of parts) { if (typeof part.points.anchor === 'undefined') anchorPoint = false if (typeof part.points.gridAnchor === 'undefined') gridAnchorPoint = false } if (anchorPoint) return parts[0].points.anchor if (gridAnchorPoint) return parts[0].points.gridAnchor return new Point(0, 0) } /** Adds an attribute. This is here to make this call chainable in assignment */ Stack.prototype.attr = function (name, value, overwrite = false) { if (overwrite) this.attributes.set(name, value) else this.attributes.add(name, value) return this } /** * Generates the transforms for a stack and sets them as attributes * @param {Object} transforms a transform config object * @param {Object} transforms.move x and y coordinates for how far to translate the stack * @param {Number} transfroms.rotate the number of degrees to rotate the stack around its center * @param {Boolean} tranforms.flipX whether to flip the stack along the X axis * @param {Boolean} transforms.flipY whether to flip the stack along the Y axis */ Stack.prototype.generateTransform = function (transforms) { const { move, rotate, flipX, flipY } = transforms const generated = utils.generateStackTransform(move?.x, move?.y, rotate, flipX, flipY, this) this.attributes.remove('transform') generated.forEach((t) => this.attr('transform', t)) return this } export default Stack