123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- import {
- DxfWriter,
- point2d,
- LWPolylineFlags,
- point3d,
- TrueColor,
- pattern,
- HatchPredefinedPatterns,
- HatchBoundaryPaths,
- HatchPolylineBoundary,
- vertex,
- } from "@tarikjabiri/dxf";
- import { useStore } from "../store";
- import Zip from "jszip";
- import { LineData } from "../components/line";
- import { CircleData } from "../components/circle";
- import { Transform } from "konva/lib/Util";
- import { lineLen, lineVector, Pos, Size, verticalVectorLine, zeroEq } from "@/utils/math";
- import { RectangleData } from "../components/rectangle";
- import { useStage } from "./use-global-vars";
- import { Group } from "konva/lib/Group";
- import { Text } from "konva/lib/shapes/Text";
- import { TextData } from "../components/text";
- import { ImageData } from "../components/image";
- import { onlyId } from "@/utils/shared";
- import { ArrowData, PointerPosition } from "../components/arrow";
- import { IconData } from "../components/icon";
- import {
- useSetViewport,
- useViewer,
- useViewerInvertTransform,
- } from "./use-viewer";
- import { nextTick } from "vue";
- import { SLineData } from "../components/sequent-line";
- import { IRect } from "konva/lib/types";
- export const useGetDXF = () => {
- const store = useStore();
- const stage = useStage();
- const invMat = useViewerInvertTransform();
- const { setViewport } = useSetViewport();
- const { viewer } = useViewer();
- return async () => {
- const writer = new DxfWriter();
- const $stage = stage.value!.getNode();
- const zip = new Zip();
- const genPromises: Promise<any>[] = [];
- const fontStyle = writer.tables.styleTable.records[0];
- fontStyle.fontFileName = "SimSun";
- type PL = {
- id?: string;
- points: Pos[];
- fill?: string;
- content?: string;
- strokeWidth?: number;
- stroke?: string;
- };
- const writerPolyline = (pl: PL) => {
- if (pl.fill) {
- const polyline = new HatchPolylineBoundary();
- const boundary = new HatchBoundaryPaths();
- pl.points.forEach((p) => polyline.add(vertex(p.x, -p.y)));
- boundary.addPolylineBoundary(polyline);
- writer.addHatch(
- boundary,
- pattern({ name: HatchPredefinedPatterns.SOLID }),
- { trueColor: TrueColor.fromHex(pl.fill).toString() }
- );
- }
- writer.addLWPolyline(
- pl.points.map((p) => ({ point: point2d(p.x, -p.y) })),
- {
- flags: LWPolylineFlags.Closed,
- constantWidth: pl.strokeWidth,
- trueColor: TrueColor.fromHex(pl.stroke || "#FFFFFF").toString(),
- }
- );
- if (!pl.content) return;
- const $text = $stage.findOne<Group>(`#${pl.id}`)?.findOne<Text>(".text");
- if ($text) {
- writeText($text);
- }
- };
- const writeText = ($text: Text, sp = true) => {
- const mat = $text.getTransform();
- const fontSize = $text.fontSize() * 0.8;
- let text = $text.text();
- text = text.replace(/(\n|\r|\t)/gi, "");
- const pad = $text.padding();
- const align = $text.align();
- const textArr: { content: string; charCount: number }[] = [];
- let lineNum = 1;
- const width = $text.width();
- const charWidth = fontSize * 0.9;
- const lineCharCount = sp
- ? Math.max(Math.floor(width / charWidth), 2)
- : Number.MAX_VALUE;
- let ndx = 0;
- let prevNdx = 0;
- let charCount = 0;
- while (ndx < text.length) {
- ndx++;
- const c = /[\u4e00-\u9fff]/.test(text.charAt(ndx)) ? 2.4 : 1;
- if (charCount === lineCharCount || ndx >= text.length) {
- charCount += c;
- textArr.push({
- content: text.substring(prevNdx, ndx + 1),
- charCount,
- });
- charCount = 0;
- prevNdx = ndx;
- } else if (charCount > lineCharCount) {
- textArr.push({
- content: text.substring(prevNdx, ndx),
- charCount,
- });
- charCount = 0;
- ndx--;
- prevNdx = ndx;
- } else {
- charCount += c;
- }
- }
- textArr.forEach((item) => {
- const lineWidth = charWidth * item.charCount;
- let p = { x: pad, y: pad + lineNum * fontSize * 1.2 };
- if (align === "center") {
- p.x = (width - lineWidth) / 2;
- } else if (align === "right") {
- p.x = width - lineWidth;
- }
- const start = mat.point(p);
- const text = writer.addText(
- point3d(start.x, -start.y),
- fontSize,
- item.content,
- {
- rotation: $text.rotation(),
- // horizontalAlignment:
- // align === "center"
- // ? TextHorizontalAlignment.Center
- // : align === "right"
- // ? TextHorizontalAlignment.Right
- // : TextHorizontalAlignment.Left,
- }
- );
- text.trueColor = TrueColor.fromHex($text.fill() as string).toString();
- text.height = fontSize;
- lineNum++;
- });
- };
- const writeImage = async (imgGroup: Group, scaleCallback?: (scale: Size, box: IRect) => () => void) => {
- let curRect = imgGroup.getClientRect();
- const oldViewMat = viewer.viewMat;
- setViewport(curRect);
- await nextTick();
- const imgRect = imgGroup.getClientRect();
- const back = scaleCallback && scaleCallback({ width: imgRect.width / curRect.width, height: imgRect.height / curRect.height }, imgRect)
- await nextTick()
- const img = (await imgGroup!.toImage({
- pixelRatio: 1,
- quality: 1,
- mimeType: "image/png",
- }).catch((e) => {
- console.error(e)
- throw e
- })) as HTMLImageElement;
- back && back()
- await nextTick()
- const start = invMat.value.point({ x: imgRect.x, y: imgRect.y + imgRect.height });
- const end = invMat.value.point({ x: imgRect.x + imgRect.width, y: imgRect.y });
- const name = onlyId().replace(/\-/g, "");
- const path = name + ".png";
- const image = writer.addImage(
- path,
- name,
- point3d(start.x, -start.y),
- img.width,
- img.height,
- 1,
- 0
- );
- image.ratio = Math.abs(end.x - start.x) / img.width;
- genPromises.push(
- fetch(img.src)
- .then((res) => res.blob())
- .then((blob) => zip.file(path, blob, {}))
- .catch(e => {
- console.error(e)
- })
- );
- viewer.setViewMat(oldViewMat);
- };
- for (const _item of store.sortItems) {
- if (_item.hide) continue;
- const type = store.getType(_item.id);
- let item;
- let mat;
- switch (type) {
- case "sequentLine":
- item = _item as SLineData;
- writer.addLWPolyline(
- item.points.map((p) => ({ point: point2d(p.x, -p.y) })),
- {
- flags: LWPolylineFlags.None,
- constantWidth: item.strokeWidth,
- trueColor: TrueColor.fromHex(item.stroke || "#FFFFFF").toString(),
- }
- );
- break;
- case "line":
- const litem = _item as LineData;
- litem.lines.forEach((line) => {
- const a = litem.points.find((p) => p.id === line.a)!;
- const b = litem.points.find((p) => p.id === line.b)!;
- // writer.addLine(
- // point3d(a.x, a.y, 0),
- // point3d(b.x, b.y, 0),
- // {
- // trueColor: TrueColor.fromHex(line.stroke || "#FFFFFF").toString(),
- // }
- // )
- writer.addLWPolyline(
- [
- { point: point3d(a.x, -a.y, 0) },
- { point: point3d(b.x, -b.y, 0) },
- ],
- {
- flags: LWPolylineFlags.None,
- constantWidth: line.strokeWidth,
- trueColor: TrueColor.fromHex(
- line.stroke || "#FFFFFF"
- ).toString(),
- }
- );
- });
- break;
- case "triangle":
- case "rectangle":
- case "polygon":
- item = _item as RectangleData;
- writerPolyline(item);
- break;
- case "circle":
- item = _item as CircleData;
- mat = new Transform(item.mat);
- const points = [];
- for (let angle = 0; angle <= 360; angle += 1) {
- const rad = angle * (Math.PI / 180);
- const x = item.radiusX * Math.cos(rad);
- const y = item.radiusY * Math.sin(rad);
- points.push(mat.point({ x, y }));
- }
- writerPolyline({ ...item, points });
- break;
- case "text":
- item = _item as TextData;
- writeText($stage.findOne<Text>(`#${item.id}`)!, !!item.width);
- break;
- case "arrow":
- item = _item as ArrowData;
- if (zeroEq(lineLen(item.points[0], item.points[1]))) {
- item = {
- ...item,
- points: [...item.points]
- }
- item.points[0] = {
- ...item.points[0],
- x: item.points[1].x - (item.pointerLength || 1)
- }
- }
- const isEnd = [PointerPosition.end, PointerPosition.all].includes(
- item.pointerPosition || PointerPosition.start
- );
- const isStart = [PointerPosition.start, PointerPosition.all].includes(
- item.pointerPosition || PointerPosition.start
- );
- for (let i = 0; i < item.points.length - 1; i++) {
- const line = [item.points[i], item.points[i + 1]];
- const nline = [...line];
- const vector = lineVector(line);
- if (isStart) {
- const start = vector
- .clone()
- .multiplyScalar(item.pointerLength! * 2)
- .add(line[0]);
- nline[0] = start;
- const l1 = verticalVectorLine(
- vector,
- start,
- item.pointerLength!
- );
- const l2 = verticalVectorLine(
- vector,
- start,
- -item.pointerLength!
- );
- writerPolyline({
- points: [line[0], l1[1], l2[1]],
- fill: item.fill,
- stroke: item.fill,
- });
- }
- if (isEnd) {
- const start = vector
- .clone()
- .multiplyScalar(-item.pointerLength! * 2)
- .add(line[1]);
- nline[1] = start;
- const l1 = verticalVectorLine(
- vector,
- start,
- item.pointerLength!
- );
- const l2 = verticalVectorLine(
- vector,
- start,
- -item.pointerLength!
- );
- writerPolyline({
- points: [line[1], l1[1], l2[1]],
- fill: item.fill,
- stroke: item.fill,
- });
- }
- writer.addLWPolyline(
- nline.map((p) => ({ point: point2d(p.x, -p.y) })),
- {
- flags: LWPolylineFlags.None,
- constantWidth: item.strokeWidth,
- trueColor: TrueColor.fromHex(item.fill || "#FFFFFF").toString(),
- }
- );
- }
- break;
- case "image":
- item = _item as ImageData;
- await writeImage($stage.findOne<Group>(`#${item.id}`)!);
- break;
- case "icon":
- const iconItem = _item as IconData;
- const pathGroup = $stage
- .findOne<Group>(`#${iconItem.id}`)!
- .findOne<Group>(".rep-position")!;
- await writeImage(pathGroup, () => {
- iconItem.strokeScaleEnabled = true
- return () => {
- iconItem.strokeScaleEnabled = false
- }
- });
- break;
- }
- }
- let dxfString = writer.stringify();
- zip.file(onlyId() + ".dxf", dxfString);
- return Promise.all(genPromises).then(() =>
- zip.generateAsync({ type: "blob" })
- );
- };
- };
|