1
0
Fork 0
freesewing/sites/shared/components/workbench/exporting/export-handler.mjs

209 lines
7.2 KiB
JavaScript
Raw Normal View History

2023-09-29 16:01:27 +02:00
// __SDEFILE__ - This file is a dependency for the stand-alone environment
import Worker from 'web-worker'
2022-08-24 12:07:08 -05:00
import fileSaver from 'file-saver'
2022-08-29 08:29:55 +02:00
import { themePlugin } from '@freesewing/plugin-theme'
import { pluginI18n } from '@freesewing/plugin-i18n'
2023-06-06 11:17:14 -05:00
import { pagesPlugin, materialPlugin } from 'shared/plugins/plugin-layout-part.mjs'
import { cutLayoutPlugin } from 'shared/plugins/plugin-cut-layout.mjs'
import { materialSettingsOrDefault } from 'shared/components/workbench/views/cut/hooks.mjs'
import { useMaterialLength } from 'shared/components/workbench/views/cut/hooks.mjs'
2023-04-15 14:51:12 -04:00
import { capitalize, formatMm } from 'shared/utils.mjs'
import {
defaultPrintSettings,
printSettingsPath,
} from 'shared/components/workbench/views/print/config.mjs'
2023-03-15 12:48:46 -05:00
import get from 'lodash.get'
2022-08-24 12:07:08 -05:00
2023-06-06 11:17:14 -05:00
export const ns = ['cut', 'plugin', 'common']
2022-08-24 12:07:08 -05:00
export const exportTypes = {
2023-06-06 15:19:11 -05:00
exportForPrinting: ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'legal', 'tabloid'],
2022-08-24 12:07:08 -05:00
exportForEditing: ['svg', 'pdf'],
2023-11-03 19:41:21 +01:00
exportAsData: ['json', 'yaml'],
2022-08-24 12:07:08 -05:00
}
2023-03-19 20:39:31 -05:00
/**
* Instantiate a pattern that uses plugins theme, i18n, and cutlist
* @param {Design} Design the design to construct the pattern from
* @param {Object} settings the settings
* @param {Object} overwrite settings to overwrite settings settings with
2023-03-19 20:39:31 -05:00
* @param {string} format the export format this pattern will be prepared for
* @param {function} t the i18n function
* @return {Pattern} a pattern
*/
const themedPattern = (Design, settings, overwrite, format, t) => {
const pattern = new Design({ ...settings, ...overwrite })
2023-03-15 12:48:46 -05:00
// add the theme and translation to the pattern
pattern.use(themePlugin, { stripped: format !== 'svg', skipGrid: ['pages'] })
pattern.use(pluginI18n, { t })
return pattern
}
2023-03-19 20:39:31 -05:00
/**
* Generate svgs of all cutting layouts for the pattern
* @param {Pattern} pattern the pattern to generate cutting layouts for
* @param {Design} design the design constructor for the pattern
* @param {Object} settings the settings
2023-03-19 20:39:31 -05:00
* @param {string} format the export format this pattern will be prepared for
* @param {function} t the i18n function
2023-06-06 11:17:14 -05:00
* @return {Object} a dictionary of svgs and related translation strings, keyed by material
2023-03-19 20:39:31 -05:00
*/
const generateCutLayouts = (pattern, Design, settings, format, t, ui) => {
2023-06-06 11:17:14 -05:00
// get the materials from the already drafted base pattern
const materials = pattern.setStores[pattern.activeSet].cutlist.getCutFabrics(
2023-03-15 12:48:46 -05:00
pattern.settings[0]
2023-06-06 11:25:53 -05:00
) || ['fabric']
2023-06-06 11:17:14 -05:00
if (!materials.length) return
2023-03-15 12:48:46 -05:00
const isImperial = settings.units === 'imperial'
2023-03-15 12:48:46 -05:00
const cutLayouts = {}
2023-06-06 11:17:14 -05:00
// each material
materials.forEach((f) => {
// get the settings and layout for that material
const materialSettings = materialSettingsOrDefault(settings.units, ui, f)
const materialLayout = get(ui, ['layouts', 'cut', f], true)
2023-03-19 20:39:31 -05:00
// make a new pattern
2023-06-06 11:17:14 -05:00
const materialPattern = themedPattern(Design, settings, { layout: materialLayout }, format, t)
// add cut layout plugin and material plugin
.use(cutLayoutPlugin(f, materialSettings.grainDirection))
.use(materialPlugin({ ...materialSettings, printStyle: true, setPatternSize: 'width' }))
2023-03-15 12:48:46 -05:00
2023-03-19 20:39:31 -05:00
// draft and render
2023-06-06 11:17:14 -05:00
materialPattern.draft()
const svg = materialPattern.render()
2023-03-19 20:39:31 -05:00
// include translations
2023-03-15 12:48:46 -05:00
cutLayouts[f] = {
svg,
2023-06-06 11:17:14 -05:00
title: t('cut:' + f),
dimensions: t('cut:materialSize', {
width: formatMm(materialSettings.sheetWidth, settings.units, 'notags'),
length: useMaterialLength(isImperial, materialPattern.height, 'notags'),
2023-03-15 12:48:46 -05:00
interpolation: { escapeValue: false },
}),
}
})
return cutLayouts
}
2022-08-24 12:07:08 -05:00
/**
* Handle exporting the draft or settings
2022-08-24 12:07:08 -05:00
* format: format to export to
* settings: the settings
* Design: the pattern constructor for the design to be exported
2022-08-24 12:07:08 -05:00
* t: a translation function to attach to the draft
* onComplete: business to perform after a successful export
* onError: business to perform on error
* */
export const handleExport = async ({
format,
settings,
Design,
design,
t,
startLoading,
stopLoading,
onComplete,
onError,
ui,
}) => {
2022-08-24 12:07:08 -05:00
// start the loading indicator
if (typeof startLoading === 'function') startLoading()
2022-08-24 12:07:08 -05:00
// get a worker going
2022-11-14 16:53:31 -06:00
const worker = new Worker(new URL('./export-worker.js', import.meta.url), { type: 'module' })
2022-08-24 12:07:08 -05:00
/*
* Guard against settings being false, which happens for
* fully default designs that do not require measurements
*/
if (settings === false) settings = {}
2022-08-24 12:07:08 -05:00
// listen for the worker's message back
worker.addEventListener('message', (e) => {
2022-08-24 12:07:08 -05:00
// on success
if (e.data.success) {
// save it out
if (e.data.blob) {
const fileType = exportTypes.exportForPrinting.indexOf(format) === -1 ? format : 'pdf'
fileSaver.saveAs(e.data.blob, `freesewing-${design || 'pattern'}.${fileType}`)
2022-08-24 12:07:08 -05:00
}
// do additional business
onComplete && onComplete(e)
}
// on error
else {
console.log(e.data.error)
onError && onError(e)
}
// stop the loader
if (typeof stopLoading === 'function') stopLoading()
2022-08-24 12:07:08 -05:00
})
// pdf settings
const pageSettings = {
...defaultPrintSettings(settings.units),
...get(ui, printSettingsPath, {}),
2022-08-24 12:07:08 -05:00
}
// arguments to pass to the worker
const workerArgs = { format, settings, pageSettings }
2022-08-24 12:07:08 -05:00
// data passed to the worker must be JSON serializable, so we can't pass functions or prototypes
// that means if it's not a data export there's more work to do before we can hand off to the worker
if (exportTypes.exportAsData.indexOf(format) === -1) {
settings.embed = false
2022-08-24 12:07:08 -05:00
// make a pattern instance for export rendering
const layout = settings.layout || ui.layouts?.print || true
let pattern = themedPattern(Design, settings, { layout }, format, t)
2022-08-24 12:07:08 -05:00
// a specified size should override the settings one
2023-08-06 18:24:14 +00:00
pageSettings.size = format
2022-08-24 12:07:08 -05:00
try {
// add pages to pdf exports
2023-08-06 18:24:14 +00:00
if (!exportTypes.exportForEditing.includes(format)) {
pattern.use(
pagesPlugin({
...pageSettings,
printStyle: true,
renderBlanks: false,
setPatternSize: true,
})
)
2022-08-24 12:07:08 -05:00
// add the strings that are used on the cover page
workerArgs.strings = {
design: capitalize(design),
2023-11-03 19:41:21 +01:00
tagline: t('common:slogan1') + '. ' + t('common:slogan2'),
url: window.location.href,
2023-06-06 11:17:14 -05:00
cuttingLayout: t('cut:cuttingLayout'),
2022-08-24 12:07:08 -05:00
}
}
// draft and render the pattern
pattern.draft()
2022-11-14 14:02:11 -06:00
workerArgs.svg = pattern.render()
2022-08-24 12:07:08 -05:00
2023-08-06 18:24:14 +00:00
if (format === 'pdf') pageSettings.size = [pattern.width, pattern.height]
2022-08-24 12:07:08 -05:00
// add the svg and pages data to the worker args
2022-11-14 14:02:11 -06:00
workerArgs.pages = pattern.setStores[pattern.activeSet].get('pages')
2023-11-03 19:41:21 +01:00
// add cutting layouts if requested (commented out for now)
2023-11-07 19:32:03 +01:00
//if (!exportTypes.exportForEditing.includes(format) && pageSettings.cutlist) {
// workerArgs.cutLayouts = generateCutLayouts(pattern, Design, settings, format, t, ui)
//}
} catch (err) {
2022-08-24 12:07:08 -05:00
console.log(err)
if (typeof stopLoading === 'function') stopLoading()
2022-08-24 12:07:08 -05:00
onError && onError(err)
}
}
2023-06-06 15:19:11 -05:00
// post a message to the worker with all needed data
worker.postMessage(workerArgs)
2022-08-24 12:07:08 -05:00
}