UNPKG

@infinite-canvas-tutorial/webcomponents

Version:
232 lines 10.1 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _ExtendedAPI_threads; import { v4 as uuidv4 } from 'uuid'; import { API, DOMAdapter, deserializePoints, } from '@infinite-canvas-tutorial/ecs'; import { Event } from './event'; import { ImageLoader } from '@loaders.gl/images'; import { load } from '@loaders.gl/core'; import { getDataURL, updateAndSelectNodes } from './utils'; import { isString, path2Absolute } from '@antv/util'; /** * Since the canvas is created in the system, we need to store them here for later use. */ export const pendingCanvases = []; // const PenMap = { // [Pen.BRUSH]: { // icon: html`<sp-icon-brush slot="icon"></sp-icon-brush>`, // label: msg(str`Brush`), // }, // [Pen.VECTOR_NETWORK]: { // icon: html`<sp-icon-vector-draw slot="icon"></sp-icon-vector-draw>`, // label: msg(str`Vector Network`), // }, // [Pen.COMMENT]: { // icon: html`<sp-icon-comment slot="icon"></sp-icon-comment>`, // label: msg(str`Comment`), // }, // }; /** * Emit CustomEvents for the canvas. */ export class ExtendedAPI extends API { constructor(stateManagement, commands, element) { super(stateManagement, commands); this.element = element; /** * Threads and comments * @see https://liveblocks.io/docs/ready-made-features/comments */ _ExtendedAPI_threads.set(this, []); } resizeCanvas(width, height) { super.resizeCanvas(width, height); this.element.dispatchEvent(new CustomEvent(Event.RESIZED, { detail: { width, height } })); } selectNodes(selected, preserveSelection = false, updateAppState = true) { super.selectNodes(selected, preserveSelection, updateAppState); this.element.dispatchEvent(new CustomEvent(Event.SELECTED_NODES_CHANGED, { detail: { selected, preserveSelection }, })); } updateNode(node, diff, updateAppState = true, skipOverrideKeys = []) { super.updateNode(node, diff, updateAppState, skipOverrideKeys); if (updateAppState) { this.element.dispatchEvent(new CustomEvent(Event.NODE_UPDATED, { detail: { node } })); } } updateNodes(nodes, updateAppState = true) { super.updateNodes(nodes, updateAppState); if (updateAppState) { this.element.dispatchEvent(new CustomEvent(Event.NODES_UPDATED, { detail: { nodes, }, })); } } deleteNodesById(ids) { const nodes = super.deleteNodesById(ids); this.element.dispatchEvent(new CustomEvent(Event.NODE_DELETED, { detail: { nodes, }, })); return nodes; } /** * Delete Canvas component */ destroy() { super.destroy(); this.element.dispatchEvent(new CustomEvent(Event.DESTROY)); } setThreads(threads) { __classPrivateFieldSet(this, _ExtendedAPI_threads, threads, "f"); } getThreads() { return __classPrivateFieldGet(this, _ExtendedAPI_threads, "f"); } /** * I18n */ setLocale(locale) { throw new Error('Method not implemented.'); } getLocale() { throw new Error('Method not implemented.'); } setThemeMode(themeMode) { this.element.dispatchEvent(new CustomEvent('theme-change', { detail: { themeMode, }, bubbles: true, composed: true, })); this.setAppState({ themeMode, }); } createImageFromFile(file_1) { return __awaiter(this, arguments, void 0, function* (file, { position, heuristicResize, } = {}) { var _a, _b; const size = { width: this.element.clientWidth, height: this.element.clientHeight, zoom: this.getAppState().cameraZoom, }; const [image, dataURL] = yield Promise.all([ load(file, ImageLoader), isString(file) ? Promise.resolve(file) : getDataURL(file), ]); let cdnUrl = dataURL; if (!isString(file) && this.upload) { cdnUrl = yield this.upload(file); } let height = image.height; let width = image.width; if (heuristicResize) { // Heuristic to calculate the size of the image. // @see https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/components/App.tsx#L10059 const minHeight = Math.max(size.height - 120, 160); // max 65% of canvas height, clamped to <300px, vh - 120px> const maxHeight = Math.min(minHeight, Math.floor(size.height * 0.5) / size.zoom); height = Math.min(image.height, maxHeight); width = height * (image.width / image.height); } const maxZIndex = this.getNodes().reduce((max, node) => { var _a; return Math.max(max, (_a = node.zIndex) !== null && _a !== void 0 ? _a : 0); }, 0); const node = { id: uuidv4(), type: 'rect', x: ((_a = position === null || position === void 0 ? void 0 : position.x) !== null && _a !== void 0 ? _a : 0) - width / 2, y: ((_b = position === null || position === void 0 ? void 0 : position.y) !== null && _b !== void 0 ? _b : 0) - height / 2, width, height, fill: cdnUrl, lockAspectRatio: true, zIndex: maxZIndex + 1, }; updateAndSelectNodes(this, this.getAppState(), [ node, ]); return node; }); } /** * Used by image model to edit with. */ createMask(nodes, relativeTo) { const canvas = DOMAdapter.get().createCanvas(relativeTo.width, relativeTo.height); const ctx = canvas.getContext('2d'); // 在图像处理和 AI 掩码(Mask)中,数值通常映射在 0 到 1 之间: // 白色 (White, 值为 1 或 255): 代表“激活”或“满分”。模型会识别这个区域,并在这里进行扩散生成。 // 黑色 (Black, 值为 0): 代表“屏蔽”或“零分”。模型会忽略这个区域,或者说将其锁定,保持原图不动。 ctx.clearRect(0, 0, relativeTo.width, relativeTo.height); ctx.fillStyle = 'black'; ctx.fillRect(0, 0, relativeTo.width, relativeTo.height); ctx.fillStyle = 'white'; ctx.strokeStyle = 'white'; nodes.forEach(node => { if (node.type === 'rect') { const { x, y, width, height } = node; ctx.fillRect(x, y, width, height); } else if (node.type === 'path') { const { d, strokeWidth, x, y } = node; ctx.beginPath(); path2Absolute(d).forEach(([command, ...data]) => { if (command === 'M') { ctx.moveTo(data[0] + x, data[1] + y); } else if (command === 'L') { ctx.lineTo(data[0] + x, data[1] + y); } else if (command === 'C') { ctx.bezierCurveTo(data[0] + x, data[1] + y, data[2] + x, data[3] + y, data[4] + x, data[5] + y); } }); ctx.closePath(); ctx.fill(); ctx.lineWidth = strokeWidth; ctx.stroke(); } else if (node.type === 'polyline') { const { points, strokeWidth, strokeLinecap, strokeLinejoin, x, y } = node; deserializePoints(points).forEach((point, index) => { if (index === 0) { ctx.moveTo(point[0] + x, point[1] + y); } else { ctx.lineTo(point[0] + x, point[1] + y); } }); ctx.lineWidth = strokeWidth; ctx.lineCap = strokeLinecap; ctx.lineJoin = strokeLinejoin; ctx.stroke(); } }); return canvas; } } _ExtendedAPI_threads = new WeakMap(); //# sourceMappingURL=API.js.map