2023-03-03 22:02:57 +00:00
|
|
|
import { name, version } from '../data.mjs'
|
|
|
|
|
|
|
|
export const scalebox = {
|
|
|
|
name: 'scalebox',
|
|
|
|
version,
|
|
|
|
macros: {
|
|
|
|
scalebox(so, { store, points, paths, scale, Point, Path }) {
|
|
|
|
// Passing `false` will remove the scalebox
|
|
|
|
if (so === false) {
|
|
|
|
for (let id of [
|
|
|
|
'__scaleboxMetricTopLeft',
|
|
|
|
'__scaleboxMetricTopRight',
|
|
|
|
'__scaleboxMetricBottomRight',
|
|
|
|
'__scaleboxMetricBottomLeft',
|
|
|
|
'__scaleboxImperialTopLeft',
|
|
|
|
'__scaleboxImperialTopRight',
|
|
|
|
'__scaleboxImperialBottomRight',
|
|
|
|
'__scaleboxImperialBottomLeft',
|
|
|
|
'__scaleboxLead',
|
|
|
|
'__scaleboxTitle',
|
|
|
|
'__scaleboxText',
|
|
|
|
'__scaleboxLink',
|
|
|
|
'__scaleboxMetric',
|
|
|
|
'__scaleboxImperial',
|
|
|
|
])
|
|
|
|
delete points[id]
|
|
|
|
for (let id of ['__scaleboxMetric', '__scaleboxImperial']) delete paths[id]
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert scale to a value between 0 and 9, inclusive.
|
|
|
|
const scaleIndex = Math.round(10 * Math.max(0.1, Math.min(1, scale))) - 1
|
|
|
|
|
|
|
|
// Metric width and height in mm and display width and height for each scale index.
|
|
|
|
const metricSizes = [
|
|
|
|
[10, 5, '1cm', '0.5cm'],
|
|
|
|
[20, 10, '2cm', '1cm'],
|
|
|
|
[30, 15, '3cm', '1.5cm'],
|
|
|
|
[40, 20, '4cm', '2cm'],
|
|
|
|
[50, 25, '5cm', '2.5cm'],
|
|
|
|
[60, 30, '6cm', '3cm'],
|
|
|
|
[70, 35, '7cm', '3.5cm'],
|
|
|
|
[80, 40, '8cm', '4cm'],
|
|
|
|
[90, 45, '9cm', '4.5cm'],
|
|
|
|
[100, 50, '10cm', '5cm'],
|
|
|
|
]
|
|
|
|
|
|
|
|
const metricWidth = metricSizes[scaleIndex][0]
|
|
|
|
const metricHeight = metricSizes[scaleIndex][1]
|
|
|
|
const metricDisplayWidth = metricSizes[scaleIndex][2]
|
|
|
|
const metricDisplayHeight = metricSizes[scaleIndex][3]
|
|
|
|
|
|
|
|
// Imperial width and height in mm and display width and heigth for each scale index.
|
|
|
|
const imperialSizes = [
|
|
|
|
[25.4 * 0.5, 25.4 * 0.25, '½″', '¼″'],
|
|
|
|
[25.4 * 0.875, 25.4 * 0.5, '⅞″', '½″'],
|
|
|
|
[25.4 * 1.25, 25.4 * 0.625, '1 ¼″', '⅝″'],
|
|
|
|
[25.4 * 1.625, 25.4 * 0.875, '1 ⅝″', '⅞″'],
|
|
|
|
[25.4 * 2, 25.4 * 1, '2″', '1″'],
|
|
|
|
[25.4 * 2.375, 25.4 * 1.25, '2 ⅜″', '1 ¼″'],
|
|
|
|
[25.4 * 2.875, 25.4 * 1.5, '2 ⅞″', '1 ½″'],
|
|
|
|
[25.4 * 3.25, 25.4 * 1.625, '3 ¼″', '1 ⅝″'],
|
|
|
|
[25.4 * 3.625, 25.4 * 1.875, '3 ⅝″', '1 ⅞″'],
|
|
|
|
[25.4 * 4, 25.4 * 2, '4″', '2″'],
|
|
|
|
]
|
|
|
|
|
|
|
|
const imperialWidth = imperialSizes[scaleIndex][0]
|
|
|
|
const imperialHeight = imperialSizes[scaleIndex][1]
|
|
|
|
const imperialDisplayWidth = imperialSizes[scaleIndex][2]
|
|
|
|
const imperialDisplayHeight = imperialSizes[scaleIndex][3]
|
|
|
|
|
|
|
|
// Box points
|
|
|
|
points.__scaleboxMetricTopLeft = new Point(
|
|
|
|
so.at.x - metricWidth / 2,
|
|
|
|
so.at.y - metricHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxMetricTopRight = new Point(
|
|
|
|
so.at.x + metricWidth / 2,
|
|
|
|
so.at.y - metricHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxMetricBottomLeft = new Point(
|
|
|
|
so.at.x - metricWidth / 2,
|
|
|
|
so.at.y + metricHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxMetricBottomRight = new Point(
|
|
|
|
so.at.x + metricWidth / 2,
|
|
|
|
so.at.y + metricHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxImperialTopLeft = new Point(
|
|
|
|
so.at.x - imperialWidth / 2,
|
|
|
|
so.at.y - imperialHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxImperialTopRight = new Point(
|
|
|
|
so.at.x + imperialWidth / 2,
|
|
|
|
so.at.y - imperialHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxImperialBottomLeft = new Point(
|
|
|
|
so.at.x - imperialWidth / 2,
|
|
|
|
so.at.y + imperialHeight / 2
|
|
|
|
)
|
|
|
|
points.__scaleboxImperialBottomRight = new Point(
|
|
|
|
so.at.x + imperialWidth / 2,
|
|
|
|
so.at.y + imperialHeight / 2
|
|
|
|
)
|
|
|
|
// Text anchor points
|
|
|
|
points.__scaleboxLead = new Point(so.at.x - 45 * scale, so.at.y - 15 * scale)
|
|
|
|
points.__scaleboxTitle = points.__scaleboxLead.shift(-90, 10 * scale)
|
|
|
|
points.__scaleboxText = points.__scaleboxTitle.shift(-90, 12 * scale)
|
|
|
|
points.__scaleboxLink = points.__scaleboxText.shift(-90, 5 * scale)
|
|
|
|
points.__scaleboxMetric = new Point(so.at.x, so.at.y + 20 * scale)
|
|
|
|
points.__scaleboxImperial = new Point(so.at.x, so.at.y + 24 * scale)
|
|
|
|
// Rotation
|
|
|
|
if (so.rotate) {
|
|
|
|
so.rotate = Number(so.rotate)
|
|
|
|
let toRotate = [
|
|
|
|
'__scaleboxMetricTopLeft',
|
|
|
|
'__scaleboxMetricTopRight',
|
|
|
|
'__scaleboxMetricBottomLeft',
|
|
|
|
'__scaleboxMetricBottomRight',
|
|
|
|
'__scaleboxImperialTopLeft',
|
|
|
|
'__scaleboxImperialTopRight',
|
|
|
|
'__scaleboxImperialBottomLeft',
|
|
|
|
'__scaleboxImperialBottomRight',
|
|
|
|
'__scaleboxLead',
|
|
|
|
'__scaleboxTitle',
|
|
|
|
'__scaleboxText',
|
|
|
|
'__scaleboxLink',
|
|
|
|
'__scaleboxMetric',
|
|
|
|
'__scaleboxImperial',
|
|
|
|
]
|
|
|
|
for (let pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at)
|
|
|
|
for (let pid of toRotate.slice(8)) {
|
|
|
|
points[pid].attributes.set(
|
|
|
|
'data-text-transform',
|
|
|
|
`rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Paths
|
|
|
|
paths.__scaleboxImperial = new Path()
|
|
|
|
.attr('class', 'scalebox imperial fill-current')
|
|
|
|
.move(points.__scaleboxImperialTopLeft)
|
|
|
|
.line(points.__scaleboxImperialBottomLeft)
|
|
|
|
.line(points.__scaleboxImperialBottomRight)
|
|
|
|
.line(points.__scaleboxImperialTopRight)
|
|
|
|
.close()
|
|
|
|
paths.__scaleboxMetric = new Path()
|
|
|
|
.attr('class', 'scalebox metric fill-bg')
|
|
|
|
.move(points.__scaleboxMetricTopLeft)
|
|
|
|
.line(points.__scaleboxMetricBottomLeft)
|
|
|
|
.line(points.__scaleboxMetricBottomRight)
|
|
|
|
.line(points.__scaleboxMetricTopRight)
|
|
|
|
.close()
|
|
|
|
// Lead
|
|
|
|
points.__scaleboxLead = points.__scaleboxLead
|
|
|
|
.attr('data-text', so.lead || 'FreeSewing')
|
|
|
|
.attr('data-text-class', 'text-sm')
|
|
|
|
// Title
|
|
|
|
if (so.title) points.__scaleboxTitle.attributes.set('data-text', so.title)
|
|
|
|
else {
|
|
|
|
let name = store.data?.name || 'No Name'
|
|
|
|
if (name.indexOf('@freesewing/') !== -1) name = name.replace('@freesewing/', '')
|
|
|
|
points.__scaleboxTitle = points.__scaleboxTitle
|
|
|
|
.attr('data-text', name)
|
|
|
|
.attr('data-text', 'v' + (store.data?.version || 'No Version'))
|
|
|
|
}
|
|
|
|
points.__scaleboxTitle.attributes.add('data-text-class', 'text-lg')
|
|
|
|
// Text
|
|
|
|
if (typeof so.text === 'string') {
|
|
|
|
points.__scaleboxText.attr('data-text', so.text)
|
|
|
|
} else {
|
|
|
|
points.__scaleboxText.attr('data-text', 'supportFreesewingBecomeAPatron')
|
|
|
|
points.__scaleboxLink = points.__scaleboxLink
|
|
|
|
.attr('data-text', 'freesewing.org/patrons/join')
|
|
|
|
.attr('data-text-class', 'text-sm fill-note')
|
|
|
|
}
|
|
|
|
points.__scaleboxText.attr('data-text-class', 'text-xs').attr('data-text-lineheight', 4)
|
|
|
|
// Instructions
|
|
|
|
points.__scaleboxMetric = points.__scaleboxMetric
|
|
|
|
.attr('data-text', 'theWhiteInsideOfThisBoxShouldMeasure')
|
|
|
|
.attr('data-text', `${metricDisplayWidth}`)
|
|
|
|
.attr('data-text', 'x')
|
|
|
|
.attr('data-text', `${metricDisplayHeight}`)
|
|
|
|
.attr('data-text-class', 'text-xs center')
|
|
|
|
points.__scaleboxImperial = points.__scaleboxImperial
|
|
|
|
.attr('data-text', 'theBlackOutsideOfThisBoxShouldMeasure')
|
|
|
|
.attr('data-text', `${imperialDisplayWidth}`)
|
|
|
|
.attr('data-text', 'x')
|
|
|
|
.attr('data-text', `${imperialDisplayHeight}`)
|
|
|
|
.attr('data-text-class', 'text-xs center ')
|
|
|
|
},
|
2023-03-04 01:36:34 +00:00
|
|
|
miniscale(so, { store, points, paths, scale, Point, Path }) {
|
|
|
|
// Passing `false` will remove the miniscale
|
|
|
|
if (so === false) {
|
|
|
|
for (const id of [
|
|
|
|
'__miniscaleMetricTopLeft',
|
|
|
|
'__miniscaleMetricTopRight',
|
|
|
|
'__miniscaleMetricBottomRight',
|
|
|
|
'__miniscaleMetricBottomLeft',
|
|
|
|
'__miniscaleImperialTopLeft',
|
|
|
|
'__miniscaleImperialTopRight',
|
|
|
|
'__miniscaleImperialBottomRight',
|
|
|
|
'__miniscaleImperialBottomLeft',
|
|
|
|
'__miniscaleMetric',
|
|
|
|
'__miniscaleImperial',
|
|
|
|
])
|
|
|
|
delete points[id]
|
|
|
|
for (const id of ['__miniscaleMetric', '__miniscaleImperial']) delete paths[id]
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert scale to a value between 0 and 5, inclusive.
|
|
|
|
const scaleIndex = Math.ceil(6 * Math.max(0.1, Math.min(1, scale))) - 1
|
|
|
|
|
|
|
|
// Metric size in mm / display value and imperial size in mm / display value for each scale index.
|
|
|
|
const sizes = [
|
|
|
|
[10, '1cm', 25.4 * 0.375, '⅜″'],
|
|
|
|
[13, '1.3cm', 25.4 * 0.5, '½″'],
|
|
|
|
[16, '1.6cm', 25.4 * 0.625, '⅝″'],
|
|
|
|
[19, '1.9cm', 25.4 * 0.75, '¾″'],
|
|
|
|
[22, '2.2cm', 25.4 * 0.875, '⅞″'],
|
|
|
|
[25, '2.5cm', 25.4 * 1, '1″'],
|
|
|
|
]
|
|
|
|
const m = sizes[scaleIndex][0] / 2
|
|
|
|
const i = sizes[scaleIndex][2] / 2
|
|
|
|
const metricDisplaySize = sizes[scaleIndex][1]
|
|
|
|
const imperialDisplaySize = sizes[scaleIndex][3]
|
|
|
|
// Box points
|
|
|
|
points.__miniscaleMetricTopLeft = new Point(so.at.x - m, so.at.y - m)
|
|
|
|
points.__miniscaleMetricTopRight = new Point(so.at.x + m, so.at.y - m)
|
|
|
|
points.__miniscaleMetricBottomLeft = new Point(so.at.x - m, so.at.y + m)
|
|
|
|
points.__miniscaleMetricBottomRight = new Point(so.at.x + m, so.at.y + m)
|
|
|
|
points.__miniscaleImperialTopLeft = new Point(so.at.x - i, so.at.y - i)
|
|
|
|
points.__miniscaleImperialTopRight = new Point(so.at.x + i, so.at.y - i)
|
|
|
|
points.__miniscaleImperialBottomLeft = new Point(so.at.x - i, so.at.y + i)
|
|
|
|
points.__miniscaleImperialBottomRight = new Point(so.at.x + i, so.at.y + i)
|
|
|
|
// Text anchor points
|
|
|
|
points.__miniscaleMetric = new Point(so.at.x, so.at.y - 2 * scale)
|
|
|
|
points.__miniscaleImperial = new Point(so.at.x, so.at.y + 8 * scale)
|
|
|
|
// Rotation
|
|
|
|
if (so.rotate) {
|
|
|
|
so.rotate = Number(so.rotate)
|
|
|
|
let toRotate = [
|
|
|
|
'__miniscaleMetricTopLeft',
|
|
|
|
'__miniscaleMetricTopRight',
|
|
|
|
'__miniscaleMetricBottomLeft',
|
|
|
|
'__miniscaleMetricBottomRight',
|
|
|
|
'__miniscaleImperialTopLeft',
|
|
|
|
'__miniscaleImperialTopRight',
|
|
|
|
'__miniscaleImperialBottomLeft',
|
|
|
|
'__miniscaleImperialBottomRight',
|
|
|
|
'__miniscaleMetric',
|
|
|
|
'__miniscaleImperial',
|
|
|
|
]
|
|
|
|
for (const pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at)
|
|
|
|
for (const pid of toRotate.slice(8)) {
|
|
|
|
points[pid].attributes.set(
|
|
|
|
'data-text-transform',
|
|
|
|
`rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Paths
|
|
|
|
paths.__miniscaleImperial = new Path()
|
|
|
|
.attr('class', 'scalebox imperial fill-current')
|
|
|
|
.move(points.__miniscaleImperialTopLeft)
|
|
|
|
.line(points.__miniscaleImperialBottomLeft)
|
|
|
|
.line(points.__miniscaleImperialBottomRight)
|
|
|
|
.line(points.__miniscaleImperialTopRight)
|
|
|
|
.close()
|
|
|
|
paths.__miniscaleMetric = new Path()
|
|
|
|
.attr('class', 'scalebox metric fill-bg')
|
|
|
|
.move(points.__miniscaleMetricTopLeft)
|
|
|
|
.line(points.__miniscaleMetricBottomLeft)
|
|
|
|
.line(points.__miniscaleMetricBottomRight)
|
|
|
|
.line(points.__miniscaleMetricTopRight)
|
|
|
|
.close()
|
|
|
|
// Text
|
|
|
|
points.__miniscaleMetric = points.__miniscaleMetric
|
|
|
|
.attr('data-text', `${metricDisplaySize} x ${metricDisplaySize}`)
|
|
|
|
.attr('data-text-class', 'text-xs center')
|
|
|
|
points.__miniscaleImperial = points.__miniscaleImperial
|
|
|
|
.attr('data-text', `${imperialDisplaySize} x ${imperialDisplaySize}`)
|
|
|
|
.attr('data-text-class', 'text-xs center ')
|
|
|
|
},
|
2023-03-03 22:02:57 +00:00
|
|
|
},
|
|
|
|
}
|