add cutting layouts to pdf export
This commit is contained in:
parent
47953e8e27
commit
05c0a9dbbf
9 changed files with 183 additions and 74 deletions
|
@ -1,6 +1,8 @@
|
||||||
canvas: Canvas
|
canvas: Canvas
|
||||||
cut: Cut
|
cut: Cut
|
||||||
|
cuttingLayout: Suggested Cutting Layout
|
||||||
fabric: Main Fabric
|
fabric: Main Fabric
|
||||||
|
fabricSize: "{length} of {width} wide material"
|
||||||
heavyCanvas: Heavy Canvas
|
heavyCanvas: Heavy Canvas
|
||||||
interfacing: Interfacing
|
interfacing: Interfacing
|
||||||
lining: Lining
|
lining: Lining
|
||||||
|
|
|
@ -8,6 +8,7 @@ export const plugin = {
|
||||||
['cutlist.removeCut', removeCut],
|
['cutlist.removeCut', removeCut],
|
||||||
['cutlist.setGrain', setGrain],
|
['cutlist.setGrain', setGrain],
|
||||||
['cutlist.setCutOnFold', setCutOnFold],
|
['cutlist.setCutOnFold', setCutOnFold],
|
||||||
|
['cutlist.getCutFabrics', getCutFabrics],
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,3 +80,20 @@ function setCutOnFold(store, p1, p2) {
|
||||||
|
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCutFabrics(store, settings) {
|
||||||
|
const cutlist = store.get('cutlist')
|
||||||
|
const list = settings.only ? [].concat(settings.only) : Object.keys(cutlist)
|
||||||
|
|
||||||
|
const fabrics = []
|
||||||
|
list.forEach((partName) => {
|
||||||
|
if (!cutlist[partName].materials) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (var m in cutlist[partName].materials) {
|
||||||
|
if (!fabrics.includes(m)) fabrics.push(m)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return fabrics
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,13 @@ import Worker from 'web-worker'
|
||||||
import fileSaver from 'file-saver'
|
import fileSaver from 'file-saver'
|
||||||
import { themePlugin } from '@freesewing/plugin-theme'
|
import { themePlugin } from '@freesewing/plugin-theme'
|
||||||
import { pluginI18n } from '@freesewing/plugin-i18n'
|
import { pluginI18n } from '@freesewing/plugin-i18n'
|
||||||
import { pagesPlugin } from '../layout/plugin-layout-part.mjs'
|
import { pagesPlugin, fabricPlugin } from '../layout/plugin-layout-part.mjs'
|
||||||
import { capitalize } from 'shared/utils.mjs'
|
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
||||||
|
import { cutLayoutPlugin } from '../layout/cut/plugin-cut-layout.mjs'
|
||||||
|
import { fabricSettingsOrDefault } from '../layout/cut/index.mjs'
|
||||||
|
import { useFabricLength } from '../layout/cut/settings.mjs'
|
||||||
|
import { capitalize, formatFraction128, formatMm } from 'shared/utils.mjs'
|
||||||
|
import get from 'lodash.get'
|
||||||
|
|
||||||
export const exportTypes = {
|
export const exportTypes = {
|
||||||
exportForPrinting: ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid'],
|
exportForPrinting: ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid'],
|
||||||
|
@ -16,8 +21,49 @@ export const defaultPdfSettings = {
|
||||||
orientation: 'portrait',
|
orientation: 'portrait',
|
||||||
margin: 10,
|
margin: 10,
|
||||||
coverPage: true,
|
coverPage: true,
|
||||||
|
cutlist: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const themedPattern = (design, gist, overwrite, format, t) => {
|
||||||
|
const pattern = new design({ ...gist, ...overwrite })
|
||||||
|
|
||||||
|
// add the theme and translation to the pattern
|
||||||
|
pattern.use(themePlugin, { stripped: format !== 'svg', skipGrid: ['pages'] })
|
||||||
|
pattern.use(pluginI18n, { t })
|
||||||
|
pattern.use(pluginCutlist)
|
||||||
|
|
||||||
|
return pattern
|
||||||
|
}
|
||||||
|
const generateCutLayouts = (pattern, design, gist, format, t) => {
|
||||||
|
const fabrics = pattern.setStores[pattern.activeSet].cutlist.getCutFabrics(
|
||||||
|
pattern.settings[0]
|
||||||
|
) || ['fabric']
|
||||||
|
if (!fabrics.length) return
|
||||||
|
|
||||||
|
const isImperial = gist.units === 'imperial'
|
||||||
|
const cutLayouts = {}
|
||||||
|
fabrics.forEach((f) => {
|
||||||
|
const fabricSettings = fabricSettingsOrDefault(gist, f)
|
||||||
|
const fabricLayout = get(gist, ['layouts', 'cuttingLayout', f], true)
|
||||||
|
const fabricPattern = themedPattern(design, gist, { layout: fabricLayout }, format, t)
|
||||||
|
.use(cutLayoutPlugin(f, fabricSettings.grainDirection))
|
||||||
|
.use(fabricPlugin({ ...fabricSettings, printStyle: true, setPatternSize: 'width' }))
|
||||||
|
|
||||||
|
fabricPattern.draft()
|
||||||
|
const svg = fabricPattern.render()
|
||||||
|
cutLayouts[f] = {
|
||||||
|
svg,
|
||||||
|
title: t('plugin:' + f),
|
||||||
|
dimensions: t('plugin:fabricSize', {
|
||||||
|
width: formatMm(fabricSettings.sheetWidth, gist.units, 'notags'),
|
||||||
|
length: useFabricLength(isImperial, fabricPattern.height, 'notags'),
|
||||||
|
interpolation: { escapeValue: false },
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return cutLayouts
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Handle exporting the draft or gist
|
* Handle exporting the draft or gist
|
||||||
* format: format to export to
|
* format: format to export to
|
||||||
|
@ -72,11 +118,7 @@ export const handleExport = async (format, gist, design, t, app, onComplete, onE
|
||||||
gist.embed = false
|
gist.embed = false
|
||||||
// make a pattern instance for export rendering
|
// make a pattern instance for export rendering
|
||||||
const layout = gist.layouts?.printingLayout || gist.layout || true
|
const layout = gist.layouts?.printingLayout || gist.layout || true
|
||||||
let pattern = new design({ ...gist, layout })
|
let pattern = themedPattern(design, gist, { layout }, format, t)
|
||||||
|
|
||||||
// add the theme and translation to the pattern
|
|
||||||
pattern.use(themePlugin, { stripped: format !== 'svg', skipGrid: ['pages'] })
|
|
||||||
pattern.use(pluginI18n, { t })
|
|
||||||
|
|
||||||
// a specified size should override the gist one
|
// a specified size should override the gist one
|
||||||
if (format !== 'pdf') {
|
if (format !== 'pdf') {
|
||||||
|
@ -100,6 +142,7 @@ export const handleExport = async (format, gist, design, t, app, onComplete, onE
|
||||||
design: capitalize(pattern.designConfig.data.name.replace('@freesewing/', '')),
|
design: capitalize(pattern.designConfig.data.name.replace('@freesewing/', '')),
|
||||||
tagline: t('common:sloganCome') + '. ' + t('common:sloganStay'),
|
tagline: t('common:sloganCome') + '. ' + t('common:sloganStay'),
|
||||||
url: window.location.href,
|
url: window.location.href,
|
||||||
|
cuttingLayout: t('plugin:cuttingLayout'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +153,11 @@ export const handleExport = async (format, gist, design, t, app, onComplete, onE
|
||||||
// add the svg and pages data to the worker args
|
// add the svg and pages data to the worker args
|
||||||
workerArgs.pages = pattern.setStores[pattern.activeSet].get('pages')
|
workerArgs.pages = pattern.setStores[pattern.activeSet].get('pages')
|
||||||
|
|
||||||
|
// add cutting layouts if requested
|
||||||
|
if (format !== 'svg' && settings.cutlist) {
|
||||||
|
workerArgs.cutLayouts = generateCutLayouts(pattern, design, gist, format, t)
|
||||||
|
}
|
||||||
|
|
||||||
// post a message to the worker with all needed data
|
// post a message to the worker with all needed data
|
||||||
worker.postMessage(workerArgs)
|
worker.postMessage(workerArgs)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ const logoSvg = `<svg viewBox="0 0 25 25">
|
||||||
* The svg uses mm internally, so when we do spatial reasoning inside the svg, we need to know values in mm
|
* The svg uses mm internally, so when we do spatial reasoning inside the svg, we need to know values in mm
|
||||||
* */
|
* */
|
||||||
const mmToPoints = 2.834645669291339
|
const mmToPoints = 2.834645669291339
|
||||||
|
const lineStart = 50
|
||||||
/**
|
/**
|
||||||
* Freesewing's first explicit class?
|
* Freesewing's first explicit class?
|
||||||
* handles pdf exporting
|
* handles pdf exporting
|
||||||
|
@ -47,12 +47,14 @@ export class PdfMaker {
|
||||||
svgHeight
|
svgHeight
|
||||||
|
|
||||||
pageCount = 0
|
pageCount = 0
|
||||||
|
lineLevel = 50
|
||||||
|
|
||||||
constructor({ svg, settings, pages, strings }) {
|
constructor({ svg, settings, pages, strings, cutLayouts }) {
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.pagesWithContent = pages.withContent
|
this.pagesWithContent = pages.withContent
|
||||||
this.svg = svg
|
this.svg = svg
|
||||||
this.strings = strings
|
this.strings = strings
|
||||||
|
this.cutLayouts = cutLayouts
|
||||||
|
|
||||||
this.initPdf()
|
this.initPdf()
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ export class PdfMaker {
|
||||||
/** make the pdf */
|
/** make the pdf */
|
||||||
async makePdf() {
|
async makePdf() {
|
||||||
await this.generateCoverPage()
|
await this.generateCoverPage()
|
||||||
|
await this.generateCutLayoutPages()
|
||||||
await this.generatePages()
|
await this.generatePages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,15 +119,19 @@ export class PdfMaker {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerLevel = await this.generateCoverPageTitle()
|
this.nextPage()
|
||||||
|
await this.generateCoverPageTitle()
|
||||||
|
await this.generateSvgPage(this.svg)
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateSvgPage(svg) {
|
||||||
//abitrary margin for visual space
|
//abitrary margin for visual space
|
||||||
let coverMargin = 85
|
let coverMargin = 85
|
||||||
let coverHeight = this.pdf.page.height - coverMargin * 2 - headerLevel
|
let coverHeight = this.pdf.page.height - coverMargin * 2 - this.lineLevel
|
||||||
let coverWidth = this.pdf.page.width - coverMargin * 2
|
let coverWidth = this.pdf.page.width - coverMargin * 2
|
||||||
|
|
||||||
// add the entire pdf to the page, so that it fills the available space as best it can
|
// add the entire pdf to the page, so that it fills the available space as best it can
|
||||||
await SVGtoPDF(this.pdf, this.svg, coverMargin, headerLevel + coverMargin, {
|
await SVGtoPDF(this.pdf, svg, coverMargin, this.lineLevel + coverMargin, {
|
||||||
width: coverWidth,
|
width: coverWidth,
|
||||||
height: coverHeight,
|
height: coverHeight,
|
||||||
assumePt: false,
|
assumePt: false,
|
||||||
|
@ -133,40 +140,50 @@ export class PdfMaker {
|
||||||
})
|
})
|
||||||
this.pageCount++
|
this.pageCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateCoverPageTitle() {
|
async generateCoverPageTitle() {
|
||||||
let lineLevel = 50
|
this.addText('FreeSewing', 28)
|
||||||
let lineStart = 50
|
.addText(this.strings.tagline, 12, 20)
|
||||||
|
.addText(this.strings.design, 48, -8)
|
||||||
this.pdf.fontSize(28)
|
|
||||||
this.pdf.text('FreeSewing', lineStart, lineLevel)
|
|
||||||
lineLevel += 28
|
|
||||||
|
|
||||||
this.pdf.fontSize(12)
|
|
||||||
this.pdf.text(this.strings.tagline, lineStart, lineLevel)
|
|
||||||
lineLevel += 12 + 20
|
|
||||||
|
|
||||||
this.pdf.fontSize(48)
|
|
||||||
this.pdf.text(this.strings.design, lineStart, lineLevel)
|
|
||||||
lineLevel += 48
|
|
||||||
|
|
||||||
await SVGtoPDF(this.pdf, logoSvg, this.pdf.page.width - lineStart - 100, lineStart, {
|
await SVGtoPDF(this.pdf, logoSvg, this.pdf.page.width - lineStart - 100, lineStart, {
|
||||||
width: 100,
|
width: 100,
|
||||||
height: lineLevel - lineStart - 8,
|
height: this.lineLevel - lineStart,
|
||||||
preserveAspectRatio: 'xMaxYMin meet',
|
preserveAspectRatio: 'xMaxYMin meet',
|
||||||
})
|
})
|
||||||
|
|
||||||
this.pdf.lineWidth(1)
|
this.pdf.lineWidth(1)
|
||||||
this.pdf
|
this.pdf
|
||||||
.moveTo(lineStart, lineLevel - 8)
|
.moveTo(lineStart, this.lineLevel)
|
||||||
.lineTo(this.pdf.page.width - lineStart, lineLevel - 8)
|
.lineTo(this.pdf.page.width - lineStart, this.lineLevel)
|
||||||
.stroke()
|
.stroke()
|
||||||
|
|
||||||
|
this.lineLevel += 8
|
||||||
this.pdf.fillColor('#888888')
|
this.pdf.fillColor('#888888')
|
||||||
this.pdf.fontSize(10)
|
this.addText(this.strings.url, 10)
|
||||||
this.pdf.text(this.strings.url, lineStart, lineLevel)
|
}
|
||||||
|
|
||||||
return lineLevel
|
async generateCutLayoutTitle(fabricTitle, fabricDimensions) {
|
||||||
|
this.addText(this.strings.cuttingLayout, 12, 2).addText(fabricTitle, 28)
|
||||||
|
|
||||||
|
this.pdf.lineWidth(1)
|
||||||
|
this.pdf
|
||||||
|
.moveTo(lineStart, this.lineLevel)
|
||||||
|
.lineTo(this.pdf.page.width - lineStart, this.lineLevel)
|
||||||
|
.stroke()
|
||||||
|
|
||||||
|
this.lineLevel += 5
|
||||||
|
this.addText(fabricDimensions, 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateCutLayoutPages() {
|
||||||
|
if (!this.settings.cutlist || !this.cutLayouts) return
|
||||||
|
|
||||||
|
for (const fabric in this.cutLayouts) {
|
||||||
|
this.nextPage()
|
||||||
|
const { title, dimensions, svg } = this.cutLayouts[fabric]
|
||||||
|
await this.generateCutLayoutTitle(title, dimensions)
|
||||||
|
await this.generateSvgPage(svg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** generate the pages of the pdf */
|
/** generate the pages of the pdf */
|
||||||
|
@ -190,11 +207,7 @@ export class PdfMaker {
|
||||||
let x = -w * this.pageWidth + startMargin
|
let x = -w * this.pageWidth + startMargin
|
||||||
let y = -h * this.pageHeight + startMargin
|
let y = -h * this.pageHeight + startMargin
|
||||||
|
|
||||||
// if there was no cover page, the first page already exists
|
this.nextPage()
|
||||||
if (this.pageCount > 0) {
|
|
||||||
// otherwise make a new page
|
|
||||||
this.pdf.addPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the pdf to the page, offset by the page distances
|
// add the pdf to the page, offset by the page distances
|
||||||
await SVGtoPDF(this.pdf, this.svg, x, y, options)
|
await SVGtoPDF(this.pdf, this.svg, x, y, options)
|
||||||
|
@ -202,4 +215,21 @@ export class PdfMaker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextPage() {
|
||||||
|
// if no pages have been made, we can use the current
|
||||||
|
this.lineLevel = lineStart
|
||||||
|
if (this.pageCount === 0) return
|
||||||
|
|
||||||
|
// otherwise make a new page
|
||||||
|
this.pdf.addPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
addText(text, fontSize, marginBottom = 0) {
|
||||||
|
this.pdf.fontSize(fontSize)
|
||||||
|
this.pdf.text(text, 50, this.lineLevel)
|
||||||
|
|
||||||
|
this.lineLevel += fontSize + marginBottom
|
||||||
|
return this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,22 +4,25 @@ import { Draft } from '../draft/index.mjs'
|
||||||
import { fabricPlugin } from '../plugin-layout-part.mjs'
|
import { fabricPlugin } from '../plugin-layout-part.mjs'
|
||||||
import { cutLayoutPlugin } from './plugin-cut-layout.mjs'
|
import { cutLayoutPlugin } from './plugin-cut-layout.mjs'
|
||||||
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
import { pluginCutlist } from '@freesewing/plugin-cutlist'
|
||||||
import { pluginFlip } from '@freesewing/plugin-flip'
|
|
||||||
import { measurementAsMm } from 'shared/utils.mjs'
|
import { measurementAsMm } from 'shared/utils.mjs'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import get from 'lodash.get'
|
import get from 'lodash.get'
|
||||||
|
|
||||||
const activeFabricPath = ['_state', 'layout', 'forCutting', 'activeFabric']
|
export const fabricSettingsOrDefault = (gist, fabric) => {
|
||||||
const useFabricSettings = (gist) => {
|
|
||||||
const isImperial = gist.units === 'imperial'
|
const isImperial = gist.units === 'imperial'
|
||||||
const sheetHeight = measurementAsMm(isImperial ? 36 : 100, gist.units)
|
const sheetHeight = measurementAsMm(isImperial ? 36 : 100, gist.units)
|
||||||
const activeFabric = get(gist, activeFabricPath) || 'fabric'
|
const gistSettings = get(gist, ['_state', 'layout', 'forCutting', 'fabric', fabric])
|
||||||
const gistSettings = get(gist, ['_state', 'layout', 'forCutting', 'fabric', activeFabric])
|
|
||||||
const sheetWidth = gistSettings?.sheetWidth || measurementAsMm(isImperial ? 54 : 120, gist.units)
|
const sheetWidth = gistSettings?.sheetWidth || measurementAsMm(isImperial ? 54 : 120, gist.units)
|
||||||
const grainDirection =
|
const grainDirection =
|
||||||
gistSettings?.grainDirection === undefined ? 90 : gistSettings.grainDirection
|
gistSettings?.grainDirection === undefined ? 90 : gistSettings.grainDirection
|
||||||
|
|
||||||
return { activeFabric, sheetWidth, grainDirection, sheetHeight }
|
return { activeFabric: fabric, sheetWidth, grainDirection, sheetHeight }
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeFabricPath = ['_state', 'layout', 'forCutting', 'activeFabric']
|
||||||
|
const useFabricSettings = (gist) => {
|
||||||
|
const activeFabric = get(gist, activeFabricPath) || 'fabric'
|
||||||
|
return fabricSettingsOrDefault(gist, activeFabric)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFabricDraft = (gist, design, fabricSettings) => {
|
const useFabricDraft = (gist, design, fabricSettings) => {
|
||||||
|
@ -42,7 +45,6 @@ const useFabricDraft = (gist, design, fabricSettings) => {
|
||||||
draft.use(cutLayoutPlugin(fabricSettings.activeFabric, fabricSettings.grainDirection))
|
draft.use(cutLayoutPlugin(fabricSettings.activeFabric, fabricSettings.grainDirection))
|
||||||
// also, pluginCutlist and pluginFlip are needed
|
// also, pluginCutlist and pluginFlip are needed
|
||||||
draft.use(pluginCutlist)
|
draft.use(pluginCutlist)
|
||||||
draft.use(pluginFlip)
|
|
||||||
|
|
||||||
// draft the pattern
|
// draft the pattern
|
||||||
draft.draft()
|
draft.draft()
|
||||||
|
@ -55,17 +57,7 @@ const useFabricDraft = (gist, design, fabricSettings) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFabricList = (draft) => {
|
const useFabricList = (draft) => {
|
||||||
const cutList = draft.setStores[0].get('cutlist')
|
return draft.setStores[0].cutlist.getCutFabrics(draft.settings[0])
|
||||||
const fabricList = ['fabric']
|
|
||||||
for (const partName in cutList) {
|
|
||||||
if (draft.settings[0].only && !draft.settings[0].only.includes(partName)) continue
|
|
||||||
|
|
||||||
for (const matName in cutList[partName].materials) {
|
|
||||||
if (!fabricList.includes(matName)) fabricList.push(matName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fabricList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bgProps = { fill: 'none' }
|
const bgProps = { fill: 'none' }
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { addToOnly } from '../plugin-layout-part.mjs'
|
import { addToOnly } from '../plugin-layout-part.mjs'
|
||||||
|
import { pluginFlip } from '@freesewing/plugin-flip'
|
||||||
|
import { pluginMirror } from '@freesewing/plugin-mirror'
|
||||||
const prefix = 'mirroredOnFold'
|
const prefix = 'mirroredOnFold'
|
||||||
|
|
||||||
// types of path operations
|
// types of path operations
|
||||||
const opTypes = ['to', 'cp1', 'cp2']
|
const opTypes = ['to', 'cp1', 'cp2']
|
||||||
|
const avoidRegx = new RegExp(`^(cutonfold|grainline|__scalebox|__miniscale|${prefix})`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The plugin to handle all business related to mirroring, rotating, and duplicating parts for the cutting layout
|
* The plugin to handle all business related to mirroring, rotating, and duplicating parts for the cutting layout
|
||||||
|
@ -90,6 +93,8 @@ export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
macros: {
|
macros: {
|
||||||
|
...pluginFlip.macros,
|
||||||
|
...pluginMirror.macros,
|
||||||
// handle mirroring on the fold and rotating to sit along the grain or bias
|
// handle mirroring on the fold and rotating to sit along the grain or bias
|
||||||
handleFoldAndGrain: ({ partCutlist, grainSpec, ignoreOnFold, bias }, { points, macro }) => {
|
handleFoldAndGrain: ({ partCutlist, grainSpec, ignoreOnFold, bias }, { points, macro }) => {
|
||||||
// if the part has cutonfold instructions
|
// if the part has cutonfold instructions
|
||||||
|
@ -114,8 +119,7 @@ export const cutLayoutPlugin = function (material, grainAngle) {
|
||||||
const mirrorPaths = []
|
const mirrorPaths = []
|
||||||
for (const p in paths) {
|
for (const p in paths) {
|
||||||
// skip ones that are hidden
|
// skip ones that are hidden
|
||||||
if (!paths[p].hidden && !p.match(/^(cutonfold|grainline|__scalebox|__miniscale)/))
|
if (!paths[p].hidden && !p.match(avoidRegx)) mirrorPaths.push(paths[p])
|
||||||
mirrorPaths.push(paths[p])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// store all the points to mirror
|
// store all the points to mirror
|
||||||
|
|
|
@ -78,7 +78,7 @@ export const GrainDirectionPicker = ({ grainDirection, activeFabric, updateGist
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFabricLength = (isImperial, height) => {
|
export const useFabricLength = (isImperial, height) => {
|
||||||
// regular conversion from mm to inches or cm
|
// regular conversion from mm to inches or cm
|
||||||
const unit = isImperial ? 25.4 : 10
|
const unit = isImperial ? 25.4 : 10
|
||||||
// conversion from inches or cm to yards or meters
|
// conversion from inches or cm to yards or meters
|
||||||
|
|
|
@ -179,11 +179,11 @@ const basePlugin = ({
|
||||||
pattern.draftPartForSet(partName, pattern.activeSet)
|
pattern.draftPartForSet(partName, pattern.activeSet)
|
||||||
|
|
||||||
// if the pattern size is supposed to be re-set to the full width and height of all pages, do that
|
// if the pattern size is supposed to be re-set to the full width and height of all pages, do that
|
||||||
if (setPatternSize) {
|
const generatedPageData = pattern.setStores[pattern.activeSet].get(partName)
|
||||||
const generatedPageData = pattern.setStores[pattern.activeSet].get('pages')
|
if (setPatternSize === true || setPatternSize === 'width')
|
||||||
pattern.width = sheetWidth * generatedPageData.cols
|
pattern.width = Math.max(pattern.width, sheetWidth * generatedPageData.cols)
|
||||||
pattern.height = sheetHeight * generatedPageData.rows
|
if (setPatternSize === true || setPatternSize === 'height')
|
||||||
}
|
pattern.height = Math.max(pattern.height, sheetHeight * generatedPageData.rows)
|
||||||
|
|
||||||
removeFromOnly(pattern, partName)
|
removeFromOnly(pattern, partName)
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,6 +24,12 @@ export const PrintLayoutSettings = (props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setCutlist = () => {
|
||||||
|
props.updateGist(
|
||||||
|
['_state', 'layout', 'forPrinting', 'page', 'cutlist'],
|
||||||
|
!props.layoutSettings.cutlist
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
@ -33,13 +39,6 @@ export const PrintLayoutSettings = (props) => {
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<PageSizePicker {...props} />
|
<PageSizePicker {...props} />
|
||||||
<PageOrientationPicker {...props} />
|
<PageOrientationPicker {...props} />
|
||||||
</div>
|
|
||||||
<div className="flex gap-4">
|
|
||||||
<ShowButtonsToggle
|
|
||||||
gist={props.gist}
|
|
||||||
updateGist={props.updateGist}
|
|
||||||
layoutSetType="forPrinting"
|
|
||||||
></ShowButtonsToggle>
|
|
||||||
<button
|
<button
|
||||||
key="export"
|
key="export"
|
||||||
onClick={props.exportIt}
|
onClick={props.exportIt}
|
||||||
|
@ -48,8 +47,15 @@ export const PrintLayoutSettings = (props) => {
|
||||||
aria-disabled={count === 0}
|
aria-disabled={count === 0}
|
||||||
>
|
>
|
||||||
<ExportIcon className="h-6 w-6 mr-2" />
|
<ExportIcon className="h-6 w-6 mr-2" />
|
||||||
{t('export')}
|
{`${t('export')} PDF`}
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<ShowButtonsToggle
|
||||||
|
gist={props.gist}
|
||||||
|
updateGist={props.updateGist}
|
||||||
|
layoutSetType="forPrinting"
|
||||||
|
></ShowButtonsToggle>
|
||||||
<button
|
<button
|
||||||
key="reset"
|
key="reset"
|
||||||
onClick={() => props.unsetGist(['layouts', 'printingLayout'])}
|
onClick={() => props.unsetGist(['layouts', 'printingLayout'])}
|
||||||
|
@ -62,8 +68,8 @@ export const PrintLayoutSettings = (props) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<label htmlFor="pageMargin" className="label mr-6">
|
<label htmlFor="pageMargin" className="label">
|
||||||
<span className="mr-2">{t('pageMargin')}</span>
|
<span className="">{t('pageMargin')}</span>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
max={50}
|
max={50}
|
||||||
|
@ -95,6 +101,15 @@ export const PrintLayoutSettings = (props) => {
|
||||||
onChange={setCoverPage}
|
onChange={setCoverPage}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<label htmlFor="cutlist" className="label">
|
||||||
|
<span className="mr-2">{t('cutlist')}</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="toggle toggle-primary"
|
||||||
|
checked={props.layoutSettings.cutlist}
|
||||||
|
onChange={setCutlist}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row font-bold items-center px-0 text-xl">
|
<div className="flex flex-row font-bold items-center px-0 text-xl">
|
||||||
<PrintIcon />
|
<PrintIcon />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue