From ac86c6b8c514cf3aa240d54602485c86a44f1eb4 Mon Sep 17 00:00:00 2001 From: Lucas Nolte Date: Fri, 2 Sep 2022 15:52:42 +0200 Subject: [PATCH 1/9] feat: refactor canvas engine so it provides canvas and context to the user --- packages/core/src/mechanic-utils.js | 1 + .../functions/fillCanvas/index.js | 29 ++++++-------- packages/engine-canvas/index.js | 39 +++++++++++++++++-- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/packages/core/src/mechanic-utils.js b/packages/core/src/mechanic-utils.js index c3fe7107..bde2da07 100644 --- a/packages/core/src/mechanic-utils.js +++ b/packages/core/src/mechanic-utils.js @@ -133,6 +133,7 @@ const extractSvgSize = el => { * Draws a dataUrl to canvas * @param {string} dataUrl - SVG string to draw * @param {HTMLCanvasElement} canvas - A canvas element to draw into + * @param {number} ratio – the pixel density to render at */ const dataUrlToCanvas = (dataUrl, canvas, ratio = 1) => new Promise((resolve, reject) => { diff --git a/packages/dsi-logo-maker/functions/fillCanvas/index.js b/packages/dsi-logo-maker/functions/fillCanvas/index.js index 0067625b..3c2b15dd 100644 --- a/packages/dsi-logo-maker/functions/fillCanvas/index.js +++ b/packages/dsi-logo-maker/functions/fillCanvas/index.js @@ -1,21 +1,21 @@ -import { getColors } from "../../utils/graphics"; +import { getColors } from '../../utils/graphics'; import { computeBaseBricks, computeBlockGeometry, precomputeBlocks, getIndexModule, -} from "../../utils/blocks"; -import { drawBlock } from "../../utils/blocks-canvas"; +} from '../../utils/blocks'; +import { drawBlock } from '../../utils/blocks-canvas'; -export const handler = ({ inputs, mechanic }) => { +export const handler = ({ inputs, mechanic, canvas, ctx }) => { const { width, height, logoWidth, logoRatio } = inputs; const rows = 2; const cols = 13; const logoHeight = Math.floor((logoWidth / logoRatio) * rows); - const words = ["DESIGN", "SYSTEMS", "INTERNATIONAL"]; + const words = ['DESIGN', 'SYSTEMS', 'INTERNATIONAL']; - let colors = getColors("Random Flag"); + let colors = getColors('Random Flag'); const blockGeometry = computeBlockGeometry(logoWidth, logoHeight, rows, cols); const baseBricks = computeBaseBricks(words, blockGeometry.fontSize); const blocksByIndex = precomputeBlocks(blockGeometry, baseBricks); @@ -32,18 +32,13 @@ export const handler = ({ inputs, mechanic }) => { if (position.x + block.width < width) { position.x += block.width; brickOffset++; - colors = getColors("Random Flag"); + colors = getColors('Random Flag'); } else { position.x = position.x - width; position.y += block.height; } } - const canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - const ctx = canvas.getContext("2d"); - ctx.save(); ctx.clearRect(0, 0, width, height); blockConfigs.forEach((blockConfig) => drawBlock(ctx, blockConfig)); @@ -53,22 +48,22 @@ export const handler = ({ inputs, mechanic }) => { export const inputs = { width: { - type: "number", + type: 'number', default: 300, min: 100, }, height: { - type: "number", + type: 'number', default: 300, min: 100, }, logoWidth: { - type: "number", + type: 'number', default: 80, min: 10, }, logoRatio: { - type: "number", + type: 'number', default: 9, max: 20, slider: true, @@ -93,5 +88,5 @@ export const presets = { }; export const settings = { - engine: require("@mechanic-design/engine-canvas"), + engine: require('@mechanic-design/engine-canvas'), }; diff --git a/packages/engine-canvas/index.js b/packages/engine-canvas/index.js index 0a33a6e1..64390785 100644 --- a/packages/engine-canvas/index.js +++ b/packages/engine-canvas/index.js @@ -1,14 +1,45 @@ -import { Mechanic } from "@mechanic-design/core"; +import { Mechanic } from '@mechanic-design/core'; -const root = document.getElementById("root"); +const root = document.getElementById('root'); export const run = (functionName, func, values, config) => { const { isPreview } = config; - root.innerHTML = ""; + root.innerHTML = ''; const mechanic = new Mechanic(func.settings, values, config); + // Preview is always going to use the pixel density of the + // screen we're currently on. + // + // Export will respect the density setting made by the user + const canvasDensity = isPreview + ? window.devicePixelRatio || 1 + : mechanic.exportDensity; + + const preparedCanvas = document.createElement('canvas'); + const preparedCanvasContext = preparedCanvas.getContext('2d'); + + if (mechanic.values.width && mechanic.values.height) { + const width = mechanic.values.width; + const height = mechanic.values.height; + + preparedCanvas.width = width * canvasDensity; + preparedCanvas.height = height * canvasDensity; + + preparedCanvas.style.width = `${width}px`; + preparedCanvas.style.height = `${height}px`; + + preparedCanvasContext.scale(canvasDensity, canvasDensity); + } else { + console.warn(`No width and height inputs found for ${functionName}. + +This is no problem though. Just make sure to set width and height on the canvas element provided by the renderer yourself. + +canvas.width = 1000; +canvas.height = 1000;`); + } + let isElAdded = false; const onFrame = (el) => { if (!isElAdded) { @@ -41,6 +72,8 @@ export const run = (functionName, func, values, config) => { state: mechanic.functionState, setState: onSetState, }, + canvas: preparedCanvas, + ctx: preparedCanvasContext, }); return mechanic; }; From 409e08d7155cb02a05832cde7581fae1c4f2d0d3 Mon Sep 17 00:00:00 2001 From: Lucas Nolte Date: Fri, 2 Sep 2022 15:56:06 +0200 Subject: [PATCH 2/9] feat: export output type information from canvas renderer to show density picker --- packages/core/app/components/SideBar.js | 46 +++++++++++++++---------- packages/engine-canvas/index.js | 2 ++ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/packages/core/app/components/SideBar.js b/packages/core/app/components/SideBar.js index 0034f5ea..4d1d5441 100644 --- a/packages/core/app/components/SideBar.js +++ b/packages/core/app/components/SideBar.js @@ -29,6 +29,7 @@ export const SideBar = ({ name, exports: functionExports, iframe, mainRef, child settings: { persistRandomOnExport, showStateExport, + engine, hidePresets, hideScaleToFit, initialScaleToFit, @@ -51,6 +52,8 @@ export const SideBar = ({ name, exports: functionExports, iframe, mainRef, child const [values, setValues] = useValues(name, inputs, exportedPresets); + const showDensitySelector = engine.isRasterExport ?? false; + const handleOnChange = (e, name, value) => { setValues(name, value); }; @@ -93,6 +96,17 @@ export const SideBar = ({ name, exports: functionExports, iframe, mainRef, child useInteractiveInputs(inputs, iframe, handleOnChange); useShortcuts(handleExport); + const DensityPicker = () => ( + + ); + return (
{children}
@@ -190,16 +204,19 @@ export const SideBar = ({ name, exports: functionExports, iframe, mainRef, child
{!showMultipleExports ? ( -
- -
+ <> + {showDensitySelector && } +
+ +
+ ) : ( <>