406 lines
12 KiB
JavaScript
406 lines
12 KiB
JavaScript
![]() |
import { shared } from './shared.mjs'
|
||
|
|
||
|
/*
|
||
|
* This is the exported part object
|
||
|
*/
|
||
|
export const back = {
|
||
|
name: 'naomiwu.back', // The name in design::part format
|
||
|
draft: draftBack, // The method to call to draft this part
|
||
|
after: shared, // Indicate the `shared` part (see import above) needs to be drafted prior to this part
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This function drafts the back panel of the skirt
|
||
|
*/
|
||
|
function draftBack({
|
||
|
Point,
|
||
|
points,
|
||
|
Path,
|
||
|
paths,
|
||
|
store,
|
||
|
part,
|
||
|
options,
|
||
|
complete,
|
||
|
sa,
|
||
|
snippets,
|
||
|
Snippet,
|
||
|
macro,
|
||
|
absoluteOptions,
|
||
|
}) {
|
||
|
/*
|
||
|
* How much we need to reduce from seat to hips
|
||
|
*/
|
||
|
const reduce = store.get('hipsQuarterReduction')
|
||
|
|
||
|
/*
|
||
|
* Do we need to add darts?
|
||
|
* Shaping happens at both back panels, so everthing we take out is doubled.
|
||
|
* In addition, shaping happens on both side seam and dart, so doubled again
|
||
|
* So only if the total reduction is more than 4x the minimal dart width do we add darts
|
||
|
*/
|
||
|
store.set(
|
||
|
'darts',
|
||
|
store.get('hipsQuarterReduction') > 4 * absoluteOptions.minDartWidth ? true : false
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
* How much shaping should we add in the panel?
|
||
|
*/
|
||
|
const shaping = store.get('darts') ? reduce - absoluteOptions.dartWidth * 2 : reduce
|
||
|
|
||
|
/*
|
||
|
* We start with drawing a simple skirt outline for the back panel
|
||
|
*/
|
||
|
points.topLeft = new Point(shaping / 2, 0)
|
||
|
points.topCp = new Point(store.get('backQuarterHips') / 2, 0)
|
||
|
points.topRight = new Point(
|
||
|
points.topLeft.x + store.get('backQuarterHips'),
|
||
|
absoluteOptions.waistSlant
|
||
|
)
|
||
|
points.bottomLeft = new Point(0, points.topRight.y + absoluteOptions.length)
|
||
|
points.bottomRight = new Point(store.get('backQuarterSeat'), points.bottomLeft.y)
|
||
|
|
||
|
/*
|
||
|
* To find the top of the dart is easy if the waistline is a straight line.
|
||
|
* However, if the `waistSlant` option is non-zero, the waistline will be a curve.
|
||
|
* So we need to follow that curve to find a point on it to use as the middle for the dart.
|
||
|
* Store the hipline curve/line so we can re-use it later, but hide it from the output.
|
||
|
*/
|
||
|
paths.hipLine =
|
||
|
options.waistSlant > 0
|
||
|
? new Path().move(points.topRight)._curve(points.topCp, points.topLeft).hide()
|
||
|
: new Path().move(points.topRight).line(points.topLeft).hide()
|
||
|
|
||
|
/*
|
||
|
* Store the waist length so we can accurately notch the waistband
|
||
|
*/
|
||
|
store.set('backHipLength', paths.hipLine.length())
|
||
|
|
||
|
/*
|
||
|
* Add back darts, but only if they are not too narrow to sew
|
||
|
*/
|
||
|
if (store.get('darts')) {
|
||
|
/*
|
||
|
* Find the middle of the hipline
|
||
|
*/
|
||
|
points.dartTopMiddle = paths.hipLine.shiftFractionAlong(0.5)
|
||
|
/*
|
||
|
* Bottom of the dart is controlled by the dart length option which is a factor
|
||
|
* of the distance between hipline and seatline.
|
||
|
*/
|
||
|
points.dartTip = points.dartTopMiddle.shift(-90, absoluteOptions.dartLength)
|
||
|
/*
|
||
|
* Now open up the dart
|
||
|
*/
|
||
|
const len = store.get('backHipLength')
|
||
|
points.dartRight = paths.hipLine.shiftAlong(len / 2 - absoluteOptions.dartWidth)
|
||
|
points.dartLeft = paths.hipLine.shiftAlong(len / 2 + absoluteOptions.dartWidth)
|
||
|
/*
|
||
|
* Finally, move the topRight point outwards to compensate for the draft shaping
|
||
|
* If the hipLine is curved, this is not a 100% accurate match as we need to extende the
|
||
|
* curve further than it goes. However, by going in a straight line from the dartRight
|
||
|
* to the topRight point, we will follow the general direction of the curve and things will
|
||
|
* smooth out
|
||
|
*/
|
||
|
points.topRight = points.dartRight.shiftOutwards(points.topRight, absoluteOptions.dartWidth * 2)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Draw the back pockets, or at least their outline
|
||
|
* We only create the points here, we will only include this outline of the user requests a
|
||
|
* complete pattern (see below)
|
||
|
*/
|
||
|
points.waistCenter = points.topLeft.shiftFractionTowards(points.topRight, 0.5)
|
||
|
points.hemCenter = new Point(points.waistCenter.x, points.bottomRight.y)
|
||
|
points.pocketBottomRight = points.hemCenter.shiftFractionTowards(points.bottomRight, 0.75)
|
||
|
points.pocketBottomLeft = points.hemCenter.shiftFractionTowards(points.bottomRight, -0.75)
|
||
|
points.pocketTopRight = points.pocketBottomRight.shift(
|
||
|
-90,
|
||
|
points.pocketBottomRight.dy(points.topRight) * options.backPocketDepth
|
||
|
)
|
||
|
points.pocketTopLeft = new Point(points.pocketBottomLeft.x, points.pocketTopRight.y)
|
||
|
points.chamferLeft = points.pocketBottomLeft.shiftFractionTowards(
|
||
|
points.pocketBottomRight,
|
||
|
options.backPocketChamferSize
|
||
|
)
|
||
|
points.chamferRight = points.pocketBottomRight.shiftFractionTowards(
|
||
|
points.pocketBottomLeft,
|
||
|
options.backPocketChamferSize
|
||
|
)
|
||
|
points.chamferLeftTop = points.chamferLeft.rotate(90, points.pocketBottomLeft)
|
||
|
points.chamferRightTop = new Point(points.pocketBottomRight.x, points.chamferLeftTop.y)
|
||
|
|
||
|
/*
|
||
|
* Also draw the back pocket flap outline
|
||
|
* We only create the points here, we will only include this outline of the user requests a
|
||
|
* complete pattern (see below)
|
||
|
*/
|
||
|
points.flapTopLeft = points.pocketTopRight.shiftFractionTowards(points.pocketTopLeft, 1.02)
|
||
|
points.flapTopRight = points.pocketTopLeft.shiftFractionTowards(points.pocketTopRight, 1.02)
|
||
|
points.flapBottomLeft = points.flapTopLeft.shift(
|
||
|
-90,
|
||
|
points.flapTopLeft.dy(points.pocketBottomLeft) / 3
|
||
|
)
|
||
|
points.flapBottomRight = points.flapTopRight.shift(
|
||
|
-90,
|
||
|
points.flapTopLeft.dy(points.pocketBottomLeft) / 4
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
* Draw the actual seamline
|
||
|
*/
|
||
|
paths.seam = new Path()
|
||
|
.move(points.topLeft)
|
||
|
.line(points.bottomLeft)
|
||
|
.line(points.bottomRight)
|
||
|
.line(points.topRight)
|
||
|
if (store.get('darts')) {
|
||
|
paths.seam = paths.seam
|
||
|
.join(paths.hipLine.split(points.dartRight).shift())
|
||
|
.line(points.dartTip)
|
||
|
.line(points.dartLeft)
|
||
|
.join(paths.hipLine.split(points.dartLeft).pop())
|
||
|
} else paths.seam._curve(points.topCp, points.topLeft)
|
||
|
|
||
|
/*
|
||
|
* Apply CSS classes and close the seamline path
|
||
|
*/
|
||
|
paths.seam.addClass('fabric').close()
|
||
|
|
||
|
/*
|
||
|
* Draw the outline of the back pocket on the pattern in dashed line so that people
|
||
|
* have a visual guide for where the pocket should go when constructing the skirt
|
||
|
* (but only if the user wants a complete pattern)
|
||
|
*/
|
||
|
paths.pocket = new Path()
|
||
|
.move(points.pocketTopLeft)
|
||
|
.line(points.chamferLeftTop)
|
||
|
.line(points.chamferLeft)
|
||
|
.line(points.chamferRight)
|
||
|
.line(points.chamferRightTop)
|
||
|
.line(points.pocketTopRight)
|
||
|
.line(points.pocketTopLeft)
|
||
|
.close()
|
||
|
.addClass('note dashed stroke-sm')
|
||
|
.hide()
|
||
|
|
||
|
/*
|
||
|
* Does the user want seam allowance (sa) included on the pattern?
|
||
|
*/
|
||
|
if (sa) {
|
||
|
/*
|
||
|
* Our dart complicates matters, so we need a version without the dart as the SA base
|
||
|
* We also need to make sure the hem allowance is different/bigger
|
||
|
*/
|
||
|
paths.saBase = new Path()
|
||
|
.move(points.topLeft)
|
||
|
.line(points.bottomLeft)
|
||
|
.line(points.bottomLeft.shift(-90, 2 * sa)) // extra hem SA
|
||
|
.line(points.bottomRight.shift(-90, 2 * sa)) // extra hem SA
|
||
|
.line(points.bottomRight)
|
||
|
.line(points.topRight)
|
||
|
.join(paths.hipLine)
|
||
|
.close()
|
||
|
.hide()
|
||
|
paths.sa = paths.saBase.offset(sa).attr('class', 'fabric sa')
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Store the side seam length so we can match it in the front part
|
||
|
*/
|
||
|
store.set('sideSeam', points.topRight.dist(points.bottomRight))
|
||
|
|
||
|
/*
|
||
|
* If the user wants a complete pattern, let's add some more guidance
|
||
|
*/
|
||
|
if (complete) {
|
||
|
/*
|
||
|
* Show the pocket outline
|
||
|
*/
|
||
|
paths.pocket.unhide()
|
||
|
|
||
|
/*
|
||
|
* Some thing with the pocket flap. Note that drawing both pocket and pocket flap
|
||
|
* also helps people know which side is up, so to speak.
|
||
|
*/
|
||
|
paths.flap = new Path()
|
||
|
.move(points.flapTopRight)
|
||
|
.line(points.flapTopLeft)
|
||
|
.line(points.flapBottomLeft)
|
||
|
.line(points.flapBottomRight)
|
||
|
.line(points.flapTopRight)
|
||
|
.close()
|
||
|
.addClass('note dashed stroke-sm')
|
||
|
|
||
|
/*
|
||
|
* Add a note on the center back seam (CB) to clarify this is center back
|
||
|
*/
|
||
|
paths.cb = new Path()
|
||
|
.move(points.bottomLeft)
|
||
|
.line(points.topLeft)
|
||
|
.addText('centerBack', 'center fill-note text-sm')
|
||
|
.attr('data-text-dy', 8)
|
||
|
/*
|
||
|
* Add a note on the side seam to clarify this is the side
|
||
|
*/
|
||
|
paths.side = new Path()
|
||
|
.move(points.bottomRight)
|
||
|
.line(points.topRight)
|
||
|
.addClass('hidden')
|
||
|
.addText('sideSeam', 'center fill-note text-sm')
|
||
|
.attr('data-text-dy', -1)
|
||
|
/*
|
||
|
* Add a note on the hem to clarify this is the hem
|
||
|
*/
|
||
|
paths.hem = new Path()
|
||
|
.move(points.bottomLeft)
|
||
|
.line(points.bottomRight)
|
||
|
.addClass('hidden')
|
||
|
.addText('hem', 'center fill-note text-sm')
|
||
|
.attr('data-text-dy', -1)
|
||
|
/*
|
||
|
* Add a note on the top seam to clarify this is where the waistband shoud be attached
|
||
|
*/
|
||
|
points.topRight
|
||
|
.addText('attachWaistband', 'fill-note right text-sm')
|
||
|
.attr('data-text-dy', 8)
|
||
|
.attr('data-text-dx', -8)
|
||
|
points.topLeft
|
||
|
.addText('attachWaistband', 'fill-note left text-sm')
|
||
|
.attr('data-text-dy', 8)
|
||
|
.attr('data-text-dx', 8)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Annotations
|
||
|
*/
|
||
|
|
||
|
// Cutlist
|
||
|
store.cutlist.setCut({ cut: 2, from: 'fabric' })
|
||
|
|
||
|
/*
|
||
|
* Add skully, the FreeSewing logo :)
|
||
|
*/
|
||
|
points.logo = points.topLeft
|
||
|
.shiftFractionTowards(points.bottomLeft, 0.3)
|
||
|
.shift(0, points.topRight.x / 4)
|
||
|
snippets.logo = new Snippet('logo', points.logo)
|
||
|
|
||
|
/*
|
||
|
* Add a title for this part
|
||
|
*/
|
||
|
points.title = points.logo.shift(-90, 70)
|
||
|
macro('title', {
|
||
|
at: points.title,
|
||
|
nr: 1,
|
||
|
title: 'back',
|
||
|
})
|
||
|
|
||
|
/*
|
||
|
* Add a grainline to indicate the fabric grain
|
||
|
*/
|
||
|
points.grainlineTop = points.topRight.shift(225, 25)
|
||
|
points.grainlineBottom = new Point(points.grainlineTop.x, points.bottomRight.y - 25)
|
||
|
macro('grainline', {
|
||
|
from: points.grainlineBottom,
|
||
|
to: points.grainlineTop,
|
||
|
})
|
||
|
|
||
|
/*
|
||
|
* Add (back) notches
|
||
|
*/
|
||
|
const notches = ['pocketTopLeft', 'pocketTopRight']
|
||
|
if (store.get('darts')) notches.push('dartLeft', 'dartRight', 'dartTip')
|
||
|
macro('sprinkle', {
|
||
|
snippet: 'bnotch',
|
||
|
on: notches,
|
||
|
})
|
||
|
|
||
|
// Add dimensions
|
||
|
if (points.topLeft.x > points.bottomLeft.x) {
|
||
|
macro('hd', {
|
||
|
id: 'bottomWidth',
|
||
|
from: points.bottomLeft,
|
||
|
to: points.bottomRight,
|
||
|
y: points.bottomLeft.y + 3 * sa + 30,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'topLeftToBottomWidth',
|
||
|
from: points.topLeft,
|
||
|
to: points.bottomRight,
|
||
|
y: points.bottomLeft.y + 3 * sa + 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'wCbWaistToSideWaist',
|
||
|
from: points.topLeft,
|
||
|
to: points.topRight,
|
||
|
y: points.topLeft.y - sa - 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'topWidth',
|
||
|
from: points.bottomLeft,
|
||
|
to: points.topRight,
|
||
|
y: points.topLeft.y - sa - 30,
|
||
|
})
|
||
|
} else {
|
||
|
macro('hd', {
|
||
|
id: 'bottomWidth',
|
||
|
from: points.bottomLeft,
|
||
|
to: points.bottomRight,
|
||
|
y: points.bottomLeft.y + 3 * sa + 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'topLeftToBottomWidth',
|
||
|
from: points.topLeft,
|
||
|
to: points.bottomRight,
|
||
|
y: points.bottomLeft.y + 3 * sa + 30,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'bottomLeftToTopWidth',
|
||
|
from: points.bottomLeft,
|
||
|
to: points.topRight,
|
||
|
y: points.topLeft.y - sa - 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'topWidth',
|
||
|
from: points.topLeft,
|
||
|
to: points.topRight,
|
||
|
y: points.topLeft.y - sa - 30,
|
||
|
})
|
||
|
}
|
||
|
if (store.get('darts')) {
|
||
|
macro('hd', {
|
||
|
id: 'topLeftToDartWidth',
|
||
|
from: points.topLeft,
|
||
|
to: points.dartLeft,
|
||
|
y: points.topLeft.y + 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'topRightToDartWidth',
|
||
|
from: points.dartRight,
|
||
|
to: points.topRight,
|
||
|
y: points.topLeft.y + 15,
|
||
|
})
|
||
|
macro('hd', {
|
||
|
id: 'dartWidth',
|
||
|
from: points.dartLeft,
|
||
|
to: points.dartRight,
|
||
|
y: points.dartTip.y + 15,
|
||
|
})
|
||
|
macro('vd', {
|
||
|
id: 'dartLength',
|
||
|
from: points.dartTip,
|
||
|
to: points.dartRight,
|
||
|
x: points.dartRight.x + 15,
|
||
|
})
|
||
|
}
|
||
|
macro('vd', {
|
||
|
id: 'rightHeight',
|
||
|
from: points.bottomRight,
|
||
|
to: points.topRight,
|
||
|
x: points.topRight.x + sa + 15,
|
||
|
})
|
||
|
|
||
|
return part
|
||
|
}
|