Создание дизайнерского приложения SVG на основе Canvas, которое экспортирует файлы DXF для производства.

Это гостевой пост от Ibsitam Arif. Проверьте его!

Векторная графика стала стандартом почти во всех отраслях промышленности. План обычно предоставляется в векторной форме, и машина работает соответственно. Точно так же в полиграфии дизайн печати представлен в векторной форме.

Когда мы говорим о Интернете, наиболее популярными векторными файлами являются SVG, и в этой статье мы увидим, как мы можем преобразовать SVG в DXF; популярный векторный файл для 2D- и 3D-моделей, созданный AutoDesk, и он популярен для экспорта данных между различными программами САПР. У нас есть простой интерфейсный холст, который позволит пользователю создать SVG, ввод которого будет отправлен на серверную часть Express.js, где мы будем делать вызов API к Vector Express API. Vector Express — отличный API для людей, которые хотят конвертировать свои векторы в различные формы без каких-либо хлопот. В этом уроке мы используем его для преобразования полученного SVG в DXF. Итак, давайте начнем!



Что мы будем строить

Давайте представим, что у нас есть станок с ЧПУ, который может резать различные материалы. Мы хотим создать интернет-магазин, в котором наши клиенты смогут создавать различные формы и размещать заказы. Когда заказ размещен, мы хотим автоматически создать файл DXF, который мы можем отправить непосредственно на машину для производства.

Структура проекта

В этом проекте у нас есть клиентский интерфейс и бэкэнд. Давайте начнем сначала с клиентской стороны, которая будет обслуживаться нашим сервером Express.

Создайте новую папку и назовите ее по своему усмотрению. Убедитесь, что в нем есть следующие файлы.

Внешний интерфейс

HTML-файл выглядит следующим образом.

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Canvas</title>
   <link rel="stylesheet" href="index.css">
</head>
<body>
  <canvas id="canvas" height="500" width="500" ></canvas>
  <button id='ellipse' type='submit'>Ellipse</button>
  <button id='rectangle' type='submit'>Rectangle</button>
  <button id='clear' type='submit'>Clear Canvas</button>
  <button id="order" type="button">Place Order</button>
  <h3 id="success"></h3>
</body>
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/451/fabric.min.js"></script>
<script src="canvas.js" type="text/javascript"></script>
</html>

Здесь мы импортировали jQuery и fabric.js для нашего холста.

Наш файл CSS только добавляет границу к холсту. Я сделал вещи проще, но вы можете редактировать.

#canvas {
  border: 1px solid blue;
}

И, наконец, основной файл canvas.js, который отвечает за всю логику создания фигур на холсте. Мы создаем тканевый холст, который принимает идентификатор нашего HTML-холста. Это дает нам доступ к функциональности библиотеки.

var canvas = new fabric.Canvas("canvas");
var clear = document.getElementById("clear");
var rectangle = document.getElementById("rectangle");
var ellipse = document.getElementById("ellipse");
var order = document.getElementById("order");
var success = document.getElementById("success");
var isEllipse = false;
var isRectangle = false;
var circle, isDown, origX, origY;
$(rectangle).on("click", function () {
  isEllipse = false;
  isRectangle = true;
  console.log("rectangle");
});
$(ellipse).on("click", function () {
  isEllipse = true;
  isRectangle = false;
  console.log("ellipse");
});
$(clear).on("click", function () {
  var objects = canvas.getObjects();
  for (var i = 0; i < objects.length; i++) {
    canvas.remove(objects[i]);
  }
  canvas.renderAll();
});
$(order).on("click", async function () {
  let mySvg = canvas.toSVG();
  let response = await fetch("http://127.0.0.1:3000/", {
    method: "POST",
    body: mySvg,
  }).then(function (response) {
    alert("Order Placed");
  });
});
canvas.on("mouse:down", function (o) {
  isDown = true;
  var pointer = canvas.getPointer(o.e);
  origX = pointer.x;
  origY = pointer.y;
  if (isEllipse) {
    circle = new fabric.Circle({
      left: origX,
      top: origY,
      originX: "left",
      originY: "top",
      radius: pointer.x - origX,
      angle: 0,
      fill: "",
      stroke: "red",
      strokeWidth: 3,
    });
    canvas.add(circle);
  }
  if (isRectangle) {
    rectangle = new fabric.Rect({
      left: origX,
      top: origY,
      fill: "transparent",
      stroke: "red",
      strokeWidth: 3,
    });
    canvas.add(rectangle);
  }
});
canvas.on("mouse:move", function (o) {
  if (!isDown) return;
  var pointer = canvas.getPointer(o.e);
  var radius =
    Math.max(Math.abs(origY - pointer.y), Math.abs(origX - pointer.x)) / 2;
  if (isEllipse) {
    if (radius > circle.strokeWidth) {
      radius -= circle.strokeWidth / 2;
    }
    circle.set({ radius: radius });
    if (origX > pointer.x) {
      circle.set({ originX: "right" });
    } else {
      circle.set({ originX: "left" });
    }
    if (origY > pointer.y) {
      circle.set({ originY: "bottom" });
    } else {
      circle.set({ originY: "top" });
    }
    canvas.renderAll();
  }
  if (isRectangle) {
    if (origX > pointer.x) {
      rectangle.set({ left: Math.abs(pointer.x) });
    }
    if (origY > pointer.y) {
      rectangle.set({ top: Math.abs(pointer.y) });
    }
    rectangle.set({ width: Math.abs(origX - pointer.x) });
    rectangle.set({ height: Math.abs(origY - pointer.y) });
    canvas.renderAll();
  }
});
canvas.on("mouse:up", function (o) {
  isDown = false;
});

После того, как мы закончили рисовать на холсте, мы вызываем toSVG() на холсте ткани, который возвращает все на холсте в виде SVG. Затем это отправляется на серверную часть, где сохраняется SVG.

Вот что мы получим в итоге:

Давайте нарисуем несколько фигур и оформим «заказ».

После оформления заказа мы получаем оповещение и наш запрос отправляется на сервер.

Бэкенд

Для обработки SVG и DXF мы используем Express.js. Создайте новую папку и назовите ее сервером. Давайте установим следующие библиотеки, чтобы начать.

npm install body-parser cors express @smidyo/vectorexpress-nodejs

Давайте теперь создадим server.js для размещения нашего внутреннего кода.

const express = require("express");
const app = express();
const port = 3000;
const vectorExpress = require("./node_modules/@smidyo/vectorexpress-nodejs/index");
const fs = require("fs");
var cors = require("cors");
app.use(cors());
var bodyParser = require("body-parser");
app.use( express.static( __dirname + '/client' ));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.text());
app.get('/', (req, res) => {
  res.sendFile( __dirname, +'client'+'/index.html');
})
app.post("/", function (req, res) {
  let svg = req.body;
  fs.writeFile("svgFromFrontend.svg", svg, () => {
    const file = fs.readFileSync(__dirname + "/svgFromFrontend.svg");
    vectorExpress
      .convert("svg", "dxf", {
        file,
        save: true,
        path: __dirname + "/svgFromFrontendConverted.dxf",
      })
    });
  res.send("Converted");
});
app.listen(port, () => console.log(`App listening on ${port} port!`));

Посмотрим, как работает бэкенд. Во-первых, после того, как пользователь делает запрос POST, он сохраняется в новом файле SVG. Во внешнем интерфейсе мы создали 2 прямоугольника и одно затмение. SVG для него был сохранен следующим образом в той же папке со следующим содержимым.

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500" height="500" viewBox="0 0 500 500" xml:space="preserve">
<desc>Created with Fabric.js 4.5.1</desc>
<defs>
</defs>
<g transform="matrix(1 0 0 1 123.5 100.5)"  >
<rect style="stroke: rgb(255,0,0); stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-opacity: 0; fill-rule: nonzero; opacity: 1;"  x="-65" y="-48" rx="0" ry="0" width="130" height="96" />
</g>
<g transform="matrix(1 0 0 1 167.5 280.5)"  >
<circle style="stroke: rgb(255,0,0); stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;"  cx="0" cy="0" r="54" />
</g>
<g transform="matrix(1 0 0 1 164.5 410)"  >
<rect style="stroke: rgb(255,0,0); stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-opacity: 0; fill-rule: nonzero; opacity: 1;"  x="-77" y="-51.5" rx="0" ry="0" width="154" height="103" />
</g>
</svg>

Теперь это отправляется в API Vector Express с помощью его оболочки Node.js, и он возвращает нам файл DXF, сохраненный в том же каталоге.

Заключение

Благодаря этому у нас есть базовое дизайнерское приложение SVG, которое выполняет преобразование DXF. Производитель всегда может получить файл DXF из бэкенда, в то время как клиент может разместить заказ на свой вектор SVG.

Для дальнейшего развития мы должны реализовать базу данных для хранения заказов и способ доступа к нашим заказам и соответствующему файлу DXF через браузер. Мы можем даже захотеть построить это поверх существующей структуры электронной коммерции.