diff --git a/src/index.js b/src/index.js index bce89ba8..c8999af9 100644 --- a/src/index.js +++ b/src/index.js @@ -6,18 +6,70 @@ import "./styles.css"; var elements = []; -function newElement(type, x, y) { +function newElement(type, x, y, width = 0, height = 0) { const element = { type: type, x: x, y: y, - width: 0, - height: 0, + width: width, + height: height, isSelected: false }; return element; } +function exportAsPNG({ background, visibleOnly, padding = 10 }) { + clearSelection(); + drawScene(); + + let subCanvasX1 = Infinity; + let subCanvasX2 = 0; + let subCanvasY1 = Infinity; + let subCanvasY2 = 0; + + elements.forEach(element => { + subCanvasX1 = Math.min(subCanvasX1, getElementAbsoluteX1(element)); + subCanvasX2 = Math.max(subCanvasX2, getElementAbsoluteX2(element)); + subCanvasY1 = Math.min(subCanvasY1, getElementAbsoluteY1(element)); + subCanvasY2 = Math.max(subCanvasY2, getElementAbsoluteY2(element)); + }); + + let targetCanvas = canvas; + + if ( visibleOnly ) { + targetCanvas = document.createElement('canvas'); + targetCanvas.style.display = 'none'; + document.body.appendChild(targetCanvas); + targetCanvas.width = subCanvasX2 - subCanvasX1 + padding * 2; + targetCanvas.height = subCanvasY2 - subCanvasY1 + padding * 2; + const targetCanvas_ctx = targetCanvas.getContext('2d'); + + if ( background ) { + targetCanvas_ctx.fillStyle = "#FFF"; + targetCanvas_ctx.fillRect(0, 0, canvas.width, canvas.height); + } + + targetCanvas_ctx.drawImage( + canvas, + subCanvasX1 - padding, // x + subCanvasY1 - padding, // y + subCanvasX2 - subCanvasX1 + padding * 2, // width + subCanvasY2 - subCanvasY1 + padding * 2, // height + 0, + 0, + targetCanvas.width, + targetCanvas.height + ); + } + + const link = document.createElement('a'); + link.setAttribute('download', 'excalibur.png'); + link.setAttribute('href', targetCanvas.toDataURL("image/png")); + link.click(); + link.remove(); + if ( targetCanvas !== canvas ) targetCanvas.remove(); +} + function rotate(x1, y1, x2, y2, angle) { // π‘Žβ€²π‘₯=(π‘Žπ‘₯βˆ’π‘π‘₯)cosπœƒβˆ’(π‘Žπ‘¦βˆ’π‘π‘¦)sinπœƒ+𝑐π‘₯ // π‘Žβ€²π‘¦=(π‘Žπ‘₯βˆ’π‘π‘₯)sinπœƒ+(π‘Žπ‘¦βˆ’π‘π‘¦)cosπœƒ+𝑐𝑦. @@ -150,7 +202,7 @@ function clearSelection() { class App extends React.Component { componentDidMount() { this.onKeyDown = event => { - if (event.key === "Backspace") { + if (event.key === "Backspace" && event.target.nodeName !== "INPUT") { for (var i = elements.length - 1; i >= 0; --i) { if (elements[i].isSelected) { elements.splice(i, 1); @@ -188,7 +240,10 @@ class App extends React.Component { super(); this.state = { draggingElement: null, - elementType: "selection" + elementType: "selection", + exportBackground: false, + exportVisibleOnly: true, + exportPadding: 10 }; } @@ -210,7 +265,40 @@ class App extends React.Component { ); }; - return ( + return <> +
+ + + + (padding: + { + this.setState({ exportPadding: e.target.value }); + }} + disabled={!this.state.exportVisibleOnly}/> + px) +
{/* Can't use the form because ElementOption is re-defined on every render, which would blow up and re-create the entire DOM tree, @@ -352,7 +440,7 @@ class App extends React.Component { }} />
- ); + ; } } diff --git a/src/styles.css b/src/styles.css index f96dc647..7c3721cf 100644 --- a/src/styles.css +++ b/src/styles.css @@ -3,3 +3,24 @@ font-family: "Virgil"; src: url("https://uploads.codesandbox.io/uploads/user/ed077012-e728-4a42-8395-cbd299149d62/AflB-FG_Virgil.ttf"); } + +.exportWrapper { + margin-bottom: 10px; + display: flex; + align-items: center; +} +.exportWrapper label { + display: flex; + align-items: center; + margin: 0 5px; +} + +.exportWrapper button { + margin-right: 10px; +} + +.exportWrapper input[type="number"] { + width: 40px; + padding: 2px; + margin-left: 10px; +}