123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- import { genBound, onlyId } from "@/utils/shared";
- import { Draw } from "../components/container/use-draw";
- import { SceneResource, getResource } from "./platform-resource";
- import { getBaseItem } from "@/core/components/util";
- import { LineData, defaultStyle } from "@/core/components/line";
- import {
- getInitCtx,
- normalLineData,
- } from "@/core/components/line/attach-server";
- import { getIconStyle, IconData } from "@/core/components/icon";
- import { defaultStyle as textDefaultStyle } from "@/core/components/text";
- import { Transform } from "konva/lib/Util";
- import { ElMessage } from "element-plus";
- import { ImageData } from "@/core/components/image";
- import { Pos, Size } from "@/utils/math";
- import { watchEffect } from "vue";
- import { TextData } from "@/core/components/text";
- import { SelectSceneData } from "../dialog/ai";
- const getSizePlaceBoxImage = ({ width, height }: Size) => {
- const borderWidth = 10;
- const canvas = document.createElement("canvas");
- canvas.width = width;
- canvas.height = height;
- const ctx = canvas.getContext("2d")!;
- // 画背景白色
- ctx.fillStyle = "#fff";
- ctx.fillRect(0, 0, width, height);
- // 画边框
- ctx.lineWidth = borderWidth;
- ctx.strokeStyle = "#000"; // 黑色边框
- // 注意strokeRect位置和尺寸要配合线宽,这里我们让边框完整显示在canvas内
- ctx.strokeRect(
- borderWidth / 2,
- borderWidth / 2,
- width - borderWidth,
- height - borderWidth
- );
- return canvas.toDataURL(); // 返回图片的Data URL字符串
- };
- const getCoverShapes = (cover: SceneResource["cover"]) => {
- let geo: LineData = {
- ...getBaseItem(),
- lines: [],
- points: [],
- polygon: [],
- zIndex: -1,
- createTime: Date.now(),
- };
- if (!cover) {
- return { geo };
- }
- const geoCtx = getInitCtx();
- cover.geos.forEach((item) => {
- let a: string = onlyId(),
- b: string;
- let i = 0;
- for (i = 0; i < item.length - 1; i++) {
- b = onlyId();
- const lId = onlyId();
- const l = { id: onlyId(), a, b, ...defaultStyle };
- const p = { id: a, ...item[i] };
- geoCtx.add.points[a] = p;
- geoCtx.add.lines[lId] = l;
- geo.points.push(p);
- geo.lines.push(l);
- a = b;
- }
- const p = { id: b!, ...item[i] };
- geoCtx.add.points[b!] = p;
- geo.points.push(p);
- });
- geo = normalLineData(geo, geoCtx);
- if (!cover.thumb) return { geo };
- const width = cover.bound.x_max - cover.bound.x_min;
- const height = cover.bound.y_max - cover.bound.y_min;
- const mat = new Transform().translate(
- cover.bound.x_min + width / 2,
- cover.bound.y_min + height / 2
- );
- const thumb: ImageData = {
- ...getBaseItem(),
- createTime: geo.createTime,
- url: cover.thumb,
- mat: mat.m,
- width,
- height,
- cornerRadius: 0,
- zIndex: -2,
- };
- return { geo, thumb };
- };
- const getTaggingShapes = async (taggings: SceneResource["taggings"]) => {
- const icons: IconData[] = [];
- const images: ImageData[] = [];
- const texts: TextData[] = [];
- const now = Date.now();
- const reqs: Promise<any>[] = [];
- for (let ndx = 0; ndx < taggings.length; ndx++) {
- const item = taggings[ndx];
- const mat = new Transform(item.mat);
- if (!item.mat && item.position) {
- mat.translate(item.position.x, item.position.y);
- item.rotate && mat.rotate(item.rotate);
- }
- if (item.isText) {
- texts.push({
- ...getBaseItem(),
- ...textDefaultStyle,
- content: item.url,
- zIndex: 1,
- mat: mat.m,
- });
- continue;
- }
- const shape = {
- ...getBaseItem(),
- ...(item.size || { width: 100, height: 100 }),
- name: item.name,
- createTime: now + ndx,
- url: item.url,
- mat: mat.m,
- zIndex: 1,
- };
- if (!item.url.includes(".svg")) {
- images.push(shape);
- continue;
- }
- reqs.push(
- getIconStyle(item.url, shape.width, shape.height, item.fixed)
- .then((style) => {
- icons.push({ ...shape, ...style });
- })
- .catch(() => {})
- );
- }
- await Promise.all(reqs)
- return {
- texts,
- images,
- icons,
- };
- };
- const getDrawResourceOffset = (
- draw: Draw,
- bound: ReturnType<typeof genBound>,
- thumb?: ImageData
- ) =>
- new Promise<Pos>((resolve, reject) => {
- ElMessage.warning("请在画图面板中选择放置位置,按右键取消");
- const data = thumb ? thumb : { url: getSizePlaceBoxImage(bound.get()!) };
- const key = "place-plaform";
- draw.enterDrawShape("image", { ...data, key }, true);
- const stopWatch = watchEffect(() => {
- if (draw.drawing) return;
- stopWatch();
- const item = draw.store.items.find(
- (item) => item.key === key
- ) as ImageData;
- if (!item) {
- reject("用户已取消");
- } else {
- draw.store.delItem("image", item.id);
- resolve({
- x: item.mat[4],
- y: item.mat[5],
- });
- }
- });
- });
- const drawSceneResource = async (resource: SceneResource, draw: Draw) => {
- const { geo, thumb } = getCoverShapes(resource.cover);
- const geoKey = "scene-geo-resource";
- let offset = { x: 0, y: 0 };
- let oldGeo = draw.store.getTypeItems("line")[0];
- if (oldGeo?.itemName === geoKey) {
- const bound = genBound();
- geo.points.forEach((p) => bound.update(p));
- offset = await getDrawResourceOffset(draw, bound, thumb);
- } else if (oldGeo) {
- oldGeo.itemName = geoKey;
- } else {
- geo.itemName = geoKey;
- }
- const bound = genBound();
- geo.points.forEach((p) => {
- p.x += offset.x;
- p.y += offset.y;
- bound.update(p);
- });
- const { icons, images, texts } = await getTaggingShapes(resource.taggings);
- const tagShapes = [...icons, ...images, ...texts, thumb];
- tagShapes.forEach((shape) => {
- if (shape) {
- shape.mat[4] += offset.x;
- shape.mat[5] += offset.y;
- bound.update({ x: shape.mat[4], y: shape.mat[5] });
- }
- });
- if (oldGeo) {
- oldGeo.points = oldGeo.points.concat(geo.points);
- oldGeo.lines = oldGeo.lines.concat(geo.lines);
- oldGeo.polygon = oldGeo.polygon.concat(geo.polygon);
- draw.store.setItem("line", { id: geo.id, value: geo });
- } else {
- draw.store.addItem("line", geo);
- }
- console.log(icons, texts, images)
- draw.store.addItems("icon", icons);
- draw.store.addItems("text", texts);
- draw.store.addItems("image", images);
- if (thumb) {
- draw.store.addItem("image", thumb);
- }
- return bound.get()!;
- };
- export const drawPlatformResource = async (
- sceneData: SelectSceneData,
- draw: Draw
- ) => {
- // 默认为米,转为厘米
- const resource = await getResource({ ...sceneData, scale: 100 });
- let bound = null as ReturnType<ReturnType<typeof genBound>["get"]>;
- console.log(resource)
- await draw.history.onceTrack(async () => {
- draw.store.setConfig({ proportion: { scale: 10, unit: "mm" } });
- bound = await drawSceneResource(resource, draw);
- if (typeof resource.compass === "number") {
- draw.store.setConfig({
- compass: {
- rotation: resource.compass,
- url: draw.store.config.compass.url,
- },
- });
- }
- });
- if (!draw.viewer.size || !bound) return;
- const size = draw.viewer.size;
- if (bound.width < 10 || bound.height < 10) {
- draw.viewer.setViewMat([
- 1,
- 0,
- 0,
- 1,
- bound.center.x + size.width / 2,
- bound.center.y + size.height / 2,
- ]);
- } else {
- const viewWidth = Math.max(bound.width, size.width);
- const viewHeight = Math.max(bound.height, size.height);
- const padding = Math.max(
- Math.min((viewWidth - bound.width) / 2, (viewHeight - bound.height) / 2),
- 40
- );
- draw.viewer.setBound({ targetBound: bound, padding });
- }
- };
|