| | import { app } from '../../../scripts/app.js' |
| |
|
| | |
| | export function makeUUID() { |
| | let dt = new Date().getTime() |
| | const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { |
| | const r = ((dt + Math.random() * 16) % 16) | 0 |
| | dt = Math.floor(dt / 16) |
| | return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16) |
| | }) |
| | return uuid |
| | } |
| |
|
| | export const loadScript = ( |
| | FILE_URL, |
| | async = true, |
| | type = 'text/javascript', |
| | ) => { |
| | return new Promise((resolve, reject) => { |
| | try { |
| | |
| | const existingScript = document.querySelector(`script[src="${FILE_URL}"]`) |
| | if (existingScript) { |
| | resolve({ status: true, message: 'Script already loaded' }) |
| | return |
| | } |
| |
|
| | const scriptEle = document.createElement('script') |
| | scriptEle.type = type |
| | scriptEle.async = async |
| | scriptEle.src = FILE_URL |
| |
|
| | scriptEle.addEventListener('load', (ev) => { |
| | resolve({ status: true }) |
| | }) |
| |
|
| | scriptEle.addEventListener('error', (ev) => { |
| | reject({ |
| | status: false, |
| | message: `Failed to load the script ${FILE_URL}`, |
| | }) |
| | }) |
| |
|
| | document.body.appendChild(scriptEle) |
| | } catch (error) { |
| | reject(error) |
| | } |
| | }) |
| | } |
| | const create_documentation_stylesheet = () => { |
| | const tag = 'kj-pointseditor-stylesheet' |
| |
|
| | let styleTag = document.head.querySelector(tag) |
| |
|
| | if (!styleTag) { |
| | styleTag = document.createElement('style') |
| | styleTag.type = 'text/css' |
| | styleTag.id = tag |
| | styleTag.innerHTML = ` |
| | .points-editor { |
| | |
| | position: absolute; |
| | |
| | font: 12px monospace; |
| | line-height: 1.5em; |
| | padding: 10px; |
| | z-index: 0; |
| | overflow: hidden; |
| | } |
| | ` |
| | document.head.appendChild(styleTag) |
| | } |
| | } |
| |
|
| | loadScript('kjweb_async/svg-path-properties.min.js').catch((e) => { |
| | console.log(e) |
| | }) |
| | loadScript('kjweb_async/protovis.min.js').catch((e) => { |
| | console.log(e) |
| | }) |
| | create_documentation_stylesheet() |
| |
|
| | function chainCallback(object, property, callback) { |
| | if (object == undefined) { |
| | |
| | console.error("Tried to add callback to non-existant object") |
| | return; |
| | } |
| | if (property in object) { |
| | const callback_orig = object[property] |
| | object[property] = function () { |
| | const r = callback_orig.apply(this, arguments); |
| | callback.apply(this, arguments); |
| | return r |
| | }; |
| | } else { |
| | object[property] = callback; |
| | } |
| | } |
| | app.registerExtension({ |
| | name: 'KJNodes.PointEditor', |
| |
|
| | async beforeRegisterNodeDef(nodeType, nodeData) { |
| | if (nodeData?.name === 'PointsEditor') { |
| | chainCallback(nodeType.prototype, "onNodeCreated", function () { |
| |
|
| | hideWidgetForGood(this, this.widgets.find(w => w.name === "coordinates")) |
| | hideWidgetForGood(this, this.widgets.find(w => w.name === "neg_coordinates")) |
| | hideWidgetForGood(this, this.widgets.find(w => w.name === "bboxes")) |
| |
|
| | var element = document.createElement("div"); |
| | this.uuid = makeUUID() |
| | element.id = `points-editor-${this.uuid}` |
| |
|
| | this.previewMediaType = 'image' |
| |
|
| | this.pointsEditor = this.addDOMWidget(nodeData.name, "PointsEditorWidget", element, { |
| | serialize: false, |
| | hideOnZoom: false, |
| | }); |
| |
|
| | |
| | this.contextMenu = document.createElement("div"); |
| | this.contextMenu.id = "context-menu"; |
| | this.contextMenu.style.display = "none"; |
| | this.contextMenu.style.position = "absolute"; |
| | this.contextMenu.style.backgroundColor = "#202020"; |
| | this.contextMenu.style.minWidth = "100px"; |
| | this.contextMenu.style.boxShadow = "0px 8px 16px 0px rgba(0,0,0,0.2)"; |
| | this.contextMenu.style.zIndex = "100"; |
| | this.contextMenu.style.padding = "5px"; |
| |
|
| | function styleMenuItem(menuItem) { |
| | menuItem.style.display = "block"; |
| | menuItem.style.padding = "5px"; |
| | menuItem.style.color = "#FFF"; |
| | menuItem.style.fontFamily = "Arial, sans-serif"; |
| | menuItem.style.fontSize = "16px"; |
| | menuItem.style.textDecoration = "none"; |
| | menuItem.style.marginBottom = "5px"; |
| | } |
| | function createMenuItem(id, textContent) { |
| | let menuItem = document.createElement("a"); |
| | menuItem.href = "#"; |
| | menuItem.id = `menu-item-${id}`; |
| | menuItem.textContent = textContent; |
| | styleMenuItem(menuItem); |
| | return menuItem; |
| | } |
| |
|
| | |
| | this.menuItems = [ |
| | createMenuItem(0, "Load Image"), |
| | createMenuItem(1, "Clear Image"), |
| | ]; |
| |
|
| | |
| | this.menuItems.forEach(menuItem => { |
| | menuItem.addEventListener('mouseover', function () { |
| | this.style.backgroundColor = "gray"; |
| | }); |
| |
|
| | menuItem.addEventListener('mouseout', function () { |
| | this.style.backgroundColor = "#202020"; |
| | }); |
| | }); |
| |
|
| | |
| | this.menuItems.forEach(menuItem => { |
| | this.contextMenu.appendChild(menuItem); |
| | }); |
| |
|
| | document.body.appendChild(this.contextMenu); |
| |
|
| | this.addWidget("button", "New canvas", null, () => { |
| | if (!this.properties || !("points" in this.properties)) { |
| | this.editor = new PointsEditor(this); |
| | this.addProperty("points", this.constructor.type, "string"); |
| | this.addProperty("neg_points", this.constructor.type, "string"); |
| |
|
| | } |
| | else { |
| | this.editor = new PointsEditor(this, true); |
| | } |
| | }); |
| |
|
| | this.setSize([550, 550]); |
| | this.resizable = false; |
| | this.pointsEditor.parentEl = document.createElement("div"); |
| | this.pointsEditor.parentEl.className = "points-editor"; |
| | this.pointsEditor.parentEl.id = `points-editor-${this.uuid}` |
| | element.appendChild(this.pointsEditor.parentEl); |
| |
|
| | chainCallback(this, "onConfigure", function () { |
| | try { |
| | this.editor = new PointsEditor(this); |
| | } catch (error) { |
| | console.error("An error occurred while configuring the editor:", error); |
| | } |
| | }); |
| | chainCallback(this, "onExecuted", function (message) { |
| | let bg_image = message["bg_image"]; |
| | this.properties.imgData = { |
| | name: "bg_image", |
| | base64: bg_image |
| | }; |
| | this.editor.refreshBackgroundImage(this); |
| | }); |
| |
|
| | }); |
| | } |
| | } |
| | }) |
| |
|
| | class PointsEditor { |
| | constructor(context, reset = false) { |
| | this.node = context; |
| | this.reset = reset; |
| | const self = this; |
| |
|
| | console.log("creatingPointEditor") |
| |
|
| | this.node.pasteFile = (file) => { |
| | if (file.type.startsWith("image/")) { |
| | this.handleImageFile(file); |
| | return true; |
| | } |
| | return false; |
| | }; |
| |
|
| | this.node.onDragOver = function (e) { |
| | if (e.dataTransfer && e.dataTransfer.items) { |
| | return [...e.dataTransfer.items].some(f => f.kind === "file" && f.type.startsWith("image/")); |
| | } |
| | return false; |
| | }; |
| |
|
| | |
| | this.node.onDragDrop = (e) => { |
| | console.log("onDragDrop called"); |
| | let handled = false; |
| | for (const file of e.dataTransfer.files) { |
| | if (file.type.startsWith("image/")) { |
| | this.handleImageFile(file); |
| | handled = true; |
| | } |
| | } |
| | return handled; |
| | }; |
| |
|
| | |
| | this.createContextMenu(); |
| |
|
| | if (reset && context.pointsEditor.element) { |
| | context.pointsEditor.element.innerHTML = ''; |
| | } |
| | this.pos_coordWidget = context.widgets.find(w => w.name === "coordinates"); |
| | this.neg_coordWidget = context.widgets.find(w => w.name === "neg_coordinates"); |
| | this.pointsStoreWidget = context.widgets.find(w => w.name === "points_store"); |
| | this.widthWidget = context.widgets.find(w => w.name === "width"); |
| | this.heightWidget = context.widgets.find(w => w.name === "height"); |
| | this.bboxStoreWidget = context.widgets.find(w => w.name === "bbox_store"); |
| | this.bboxWidget = context.widgets.find(w => w.name === "bboxes"); |
| |
|
| | |
| | this.widthWidget.callback = () => { |
| | this.width = this.widthWidget.value; |
| | if (this.width > 256) { |
| | context.setSize([this.width + 45, context.size[1]]); |
| | } |
| | this.vis.width(this.width); |
| | this.updateData(); |
| | } |
| | this.heightWidget.callback = () => { |
| | this.height = this.heightWidget.value |
| | this.vis.height(this.height) |
| | context.setSize([context.size[0], this.height + 300]); |
| | this.updateData(); |
| | } |
| | this.pointsStoreWidget.callback = () => { |
| | this.points = JSON.parse(pointsStoreWidget.value).positive; |
| | this.neg_points = JSON.parse(pointsStoreWidget.value).negative; |
| | this.updateData(); |
| | } |
| | this.bboxStoreWidget.callback = () => { |
| | this.bbox = JSON.parse(bboxStoreWidget.value) |
| | this.updateData(); |
| | } |
| |
|
| | this.width = this.widthWidget.value; |
| | this.height = this.heightWidget.value; |
| | var i = 3; |
| | this.points = []; |
| | this.neg_points = []; |
| | this.bbox = [{}]; |
| | var drawing = false; |
| |
|
| | |
| | if (!reset && this.pointsStoreWidget.value != "") { |
| | this.points = JSON.parse(this.pointsStoreWidget.value).positive; |
| | this.neg_points = JSON.parse(this.pointsStoreWidget.value).negative; |
| | this.bbox = JSON.parse(this.bboxStoreWidget.value); |
| | console.log(this.bbox) |
| | } else { |
| | this.points = [ |
| | { |
| | x: this.width / 2, |
| | y: this.height / 2 |
| | } |
| | ]; |
| | this.neg_points = [ |
| | { |
| | x: 0, |
| | y: 0 |
| | } |
| | ]; |
| | const combinedPoints = { |
| | positive: this.points, |
| | negative: this.neg_points, |
| | }; |
| | this.pointsStoreWidget.value = JSON.stringify(combinedPoints); |
| | this.bboxStoreWidget.value = JSON.stringify(this.bbox); |
| | } |
| |
|
| | |
| | this.vis = new pv.Panel() |
| | .width(this.width) |
| | .height(this.height) |
| | .fillStyle("#222") |
| | .strokeStyle("gray") |
| | .lineWidth(2) |
| | .antialias(false) |
| | .margin(10) |
| | .event("mousedown", function () { |
| | if (pv.event.shiftKey && pv.event.button === 2) { |
| | let scaledMouse = { |
| | x: this.mouse().x / app.canvas.ds.scale, |
| | y: this.mouse().y / app.canvas.ds.scale |
| | }; |
| | i = self.neg_points.push(scaledMouse) - 1; |
| | self.updateData(); |
| | return this; |
| | } |
| | else if (pv.event.shiftKey) { |
| | let scaledMouse = { |
| | x: this.mouse().x / app.canvas.ds.scale, |
| | y: this.mouse().y / app.canvas.ds.scale |
| | }; |
| | i = self.points.push(scaledMouse) - 1; |
| | self.updateData(); |
| | return this; |
| | } |
| | else if (pv.event.ctrlKey) { |
| | console.log("start drawing at " + this.mouse().x / app.canvas.ds.scale + ", " + this.mouse().y / app.canvas.ds.scale); |
| | drawing = true; |
| | self.bbox[0].startX = this.mouse().x / app.canvas.ds.scale; |
| | self.bbox[0].startY = this.mouse().y / app.canvas.ds.scale; |
| | } |
| | else if (pv.event.button === 2) { |
| | self.node.contextMenu.style.display = 'block'; |
| | self.node.contextMenu.style.left = `${pv.event.clientX}px`; |
| | self.node.contextMenu.style.top = `${pv.event.clientY}px`; |
| | } |
| | }) |
| | .event("mousemove", function () { |
| | if (drawing) { |
| | self.bbox[0].endX = this.mouse().x / app.canvas.ds.scale; |
| | self.bbox[0].endY = this.mouse().y / app.canvas.ds.scale; |
| | self.vis.render(); |
| | } |
| | }) |
| | .event("mouseup", function () { |
| | console.log("end drawing at " + this.mouse().x / app.canvas.ds.scale + ", " + this.mouse().y / app.canvas.ds.scale); |
| | drawing = false; |
| | self.updateData(); |
| | }); |
| |
|
| | this.backgroundImage = this.vis.add(pv.Image).visible(false) |
| | |
| | |
| | this.bounding_box = this.vis.add(pv.Area) |
| | .data(function () { |
| | if (drawing || (self.bbox && self.bbox[0] && Object.keys(self.bbox[0]).length > 0)) { |
| | return [self.bbox[0].startX, self.bbox[0].endX]; |
| | } else { |
| | return []; |
| | } |
| | }) |
| | .bottom(function () {return self.height - Math.max(self.bbox[0].startY, self.bbox[0].endY); }) |
| | .left(function (d) {return d; }) |
| | .height(function () {return Math.abs(self.bbox[0].startY - self.bbox[0].endY);}) |
| | .fillStyle("rgba(70, 130, 180, 0.5)") |
| | .strokeStyle("steelblue") |
| | .visible(function () {return drawing || Object.keys(self.bbox[0]).length > 0; }) |
| | .add(pv.Dot) |
| | .visible(function () {return drawing || Object.keys(self.bbox[0]).length > 0; }) |
| | .data(() => { |
| | if (self.bbox && Object.keys(self.bbox[0]).length > 0) { |
| | return [{ |
| | x: self.bbox[0].endX, |
| | y: self.bbox[0].endY |
| | }]; |
| | } else { |
| | return []; |
| | } |
| | }) |
| | .left(d => d.x) |
| | .top(d => d.y) |
| | .radius(Math.log(Math.min(self.width, self.height)) * 1) |
| | .shape("square") |
| | .cursor("move") |
| | .strokeStyle("steelblue") |
| | .lineWidth(2) |
| | .fillStyle(function () { return "rgba(100, 100, 100, 0.6)"; }) |
| | .event("mousedown", pv.Behavior.drag()) |
| | .event("drag", function () { |
| | let adjustedX = this.mouse().x / app.canvas.ds.scale; |
| | let adjustedY = this.mouse().y / app.canvas.ds.scale; |
| |
|
| | |
| | adjustedX = Math.max(0, Math.min(self.vis.width(), adjustedX)); |
| | adjustedY = Math.max(0, Math.min(self.vis.height(), adjustedY)); |
| | self.bbox[0].endX = this.mouse().x / app.canvas.ds.scale; |
| | self.bbox[0].endY = this.mouse().y / app.canvas.ds.scale; |
| | self.vis.render(); |
| | }) |
| | .event("dragend", function () { |
| | self.updateData(); |
| | }); |
| |
|
| | |
| | this.vis.add(pv.Dot) |
| | .data(() => this.points) |
| | .left(d => d.x) |
| | .top(d => d.y) |
| | .radius(Math.log(Math.min(self.width, self.height)) * 4) |
| | .shape("circle") |
| | .cursor("move") |
| | .strokeStyle(function () { return i == this.index ? "#07f907" : "#139613"; }) |
| | .lineWidth(4) |
| | .fillStyle(function () { return "rgba(100, 100, 100, 0.6)"; }) |
| | .event("mousedown", pv.Behavior.drag()) |
| | .event("dragstart", function () { |
| | i = this.index; |
| | }) |
| | .event("dragend", function () { |
| | if (pv.event.button === 2 && i !== 0 && i !== self.points.length - 1) { |
| | this.index = i; |
| | self.points.splice(i--, 1); |
| | } |
| | self.updateData(); |
| |
|
| | }) |
| | .event("drag", function () { |
| | let adjustedX = this.mouse().x / app.canvas.ds.scale; |
| | let adjustedY = this.mouse().y / app.canvas.ds.scale; |
| | |
| | const panelWidth = self.vis.width(); |
| | const panelHeight = self.vis.height(); |
| |
|
| | |
| | adjustedX = Math.max(0, Math.min(panelWidth, adjustedX)); |
| | adjustedY = Math.max(0, Math.min(panelHeight, adjustedY)); |
| | self.points[this.index] = { x: adjustedX, y: adjustedY }; |
| | self.vis.render(); |
| | }) |
| |
|
| | .anchor("center") |
| | .add(pv.Label) |
| | .left(d => d.x < this.width / 2 ? d.x + 30 : d.x - 35) |
| | .top(d => d.y < this.height / 2 ? d.y + 25 : d.y - 25) |
| | .font(25 + "px sans-serif") |
| | .text(d => {return this.points.indexOf(d); }) |
| | .textStyle("#139613") |
| | .textShadow("2px 2px 2px black") |
| | .add(pv.Dot) |
| | .data(() => this.points) |
| | .left(d => d.x) |
| | .top(d => d.y) |
| | .radius(2) |
| | .shape("circle") |
| | .fillStyle("red") |
| | .lineWidth(1); |
| |
|
| | |
| | this.vis.add(pv.Dot) |
| | .data(() => this.neg_points) |
| | .left(d => d.x) |
| | .top(d => d.y) |
| | .radius(Math.log(Math.min(self.width, self.height)) * 4) |
| | .shape("circle") |
| | .cursor("move") |
| | .strokeStyle(function () { return i == this.index ? "#f91111" : "#891616"; }) |
| | .lineWidth(4) |
| | .fillStyle(function () { return "rgba(100, 100, 100, 0.6)"; }) |
| | .event("mousedown", pv.Behavior.drag()) |
| | .event("dragstart", function () { |
| | i = this.index; |
| | }) |
| | .event("dragend", function () { |
| | if (pv.event.button === 2 && i !== 0 && i !== self.neg_points.length - 1) { |
| | this.index = i; |
| | self.neg_points.splice(i--, 1); |
| | } |
| | self.updateData(); |
| |
|
| | }) |
| | .event("drag", function () { |
| | let adjustedX = this.mouse().x / app.canvas.ds.scale; |
| | let adjustedY = this.mouse().y / app.canvas.ds.scale; |
| | |
| | const panelWidth = self.vis.width(); |
| | const panelHeight = self.vis.height(); |
| |
|
| | |
| | adjustedX = Math.max(0, Math.min(panelWidth, adjustedX)); |
| | adjustedY = Math.max(0, Math.min(panelHeight, adjustedY)); |
| | self.neg_points[this.index] = { x: adjustedX, y: adjustedY }; |
| | self.vis.render(); |
| | }) |
| | .anchor("center") |
| | .add(pv.Label) |
| | .left(d => d.x < this.width / 2 ? d.x + 30 : d.x - 35) |
| | .top(d => d.y < this.height / 2 ? d.y + 25 : d.y - 25) |
| | .font(25 + "px sans-serif") |
| | .text(d => {return this.neg_points.indexOf(d); }) |
| | .textStyle("red") |
| | .textShadow("2px 2px 2px black") |
| | .add(pv.Dot) |
| | .data(() => this.neg_points) |
| | .left(d => d.x) |
| | .top(d => d.y) |
| | .radius(2) |
| | .shape("circle") |
| | .fillStyle("red") |
| | .lineWidth(1); |
| |
|
| | if (this.points.length != 0) { |
| | this.vis.render(); |
| | } |
| |
|
| | var svgElement = this.vis.canvas(); |
| | svgElement.style['zIndex'] = "2" |
| | svgElement.style['position'] = "relative" |
| | this.node.pointsEditor.element.appendChild(svgElement); |
| |
|
| | if (this.width > 256) { |
| | this.node.setSize([this.width + 45, this.node.size[1]]); |
| | } |
| | this.node.setSize([this.node.size[0], this.height + 300]); |
| | this.updateData(); |
| | this.refreshBackgroundImage(); |
| |
|
| | } |
| |
|
| | updateData = () => { |
| | if (!this.points || this.points.length === 0) { |
| | console.log("no points"); |
| | return; |
| | } |
| | const combinedPoints = { |
| | positive: this.points, |
| | negative: this.neg_points, |
| | }; |
| | this.pointsStoreWidget.value = JSON.stringify(combinedPoints); |
| | this.pos_coordWidget.value = JSON.stringify(this.points); |
| | this.neg_coordWidget.value = JSON.stringify(this.neg_points); |
| |
|
| | if (this.bbox.length != 0) { |
| | let bboxString = JSON.stringify(this.bbox); |
| | this.bboxStoreWidget.value = bboxString; |
| | this.bboxWidget.value = bboxString; |
| | } |
| | |
| | this.vis.render(); |
| | }; |
| |
|
| | handleImageLoad = (img, file, base64String) => { |
| | console.log(img.width, img.height); |
| | this.widthWidget.value = img.width; |
| | this.heightWidget.value = img.height; |
| |
|
| | if (img.width != this.vis.width() || img.height != this.vis.height()) { |
| | if (img.width > 256) { |
| | this.node.setSize([img.width + 45, this.node.size[1]]); |
| | } |
| | this.node.setSize([this.node.size[0], img.height + 300]); |
| | this.vis.width(img.width); |
| | this.vis.height(img.height); |
| | this.height = img.height; |
| | this.width = img.width; |
| | this.updateData(); |
| | } |
| | this.backgroundImage.url(file ? URL.createObjectURL(file) : `data:${this.node.properties.imgData.type};base64,${base64String}`).visible(true).root.render(); |
| | }; |
| |
|
| | processImage = (img, file) => { |
| | const canvas = document.createElement('canvas'); |
| | const ctx = canvas.getContext('2d'); |
| |
|
| | const maxWidth = 800; |
| | const maxHeight = 600; |
| | let width = img.width; |
| | let height = img.height; |
| |
|
| | |
| | if (width > height) { |
| | if (width > maxWidth) { |
| | height *= maxWidth / width; |
| | width = maxWidth; |
| | } |
| | } else { |
| | if (height > maxHeight) { |
| | width *= maxHeight / height; |
| | height = maxHeight; |
| | } |
| | } |
| |
|
| | canvas.width = width; |
| | canvas.height = height; |
| | ctx.drawImage(img, 0, 0, width, height); |
| |
|
| | |
| | const base64String = canvas.toDataURL('image/jpeg', 0.5).replace('data:', '').replace(/^.+,/, ''); |
| |
|
| | this.node.properties.imgData = { |
| | name: file.name, |
| | lastModified: file.lastModified, |
| | size: file.size, |
| | type: file.type, |
| | base64: base64String |
| | }; |
| | handleImageLoad(img, file, base64String); |
| | }; |
| |
|
| | handleImageFile = (file) => { |
| | const reader = new FileReader(); |
| | reader.onloadend = () => { |
| | const img = new Image(); |
| | img.src = reader.result; |
| | img.onload = () => processImage(img, file); |
| | }; |
| | reader.readAsDataURL(file); |
| |
|
| | const imageUrl = URL.createObjectURL(file); |
| | const img = new Image(); |
| | img.src = imageUrl; |
| | img.onload = () => this.handleImageLoad(img, file, null); |
| | }; |
| |
|
| | refreshBackgroundImage = () => { |
| | if (this.node.properties.imgData && this.node.properties.imgData.base64) { |
| | const base64String = this.node.properties.imgData.base64; |
| | const imageUrl = `data:${this.node.properties.imgData.type};base64,${base64String}`; |
| | const img = new Image(); |
| | img.src = imageUrl; |
| | img.onload = () => this.handleImageLoad(img, null, base64String); |
| | } |
| | }; |
| |
|
| | createContextMenu = () => { |
| | self = this; |
| | document.addEventListener('contextmenu', function (e) { |
| | e.preventDefault(); |
| | }); |
| |
|
| | document.addEventListener('click', function (e) { |
| | if (!self.node.contextMenu.contains(e.target)) { |
| | self.node.contextMenu.style.display = 'none'; |
| | } |
| | }); |
| |
|
| | this.node.menuItems.forEach((menuItem, index) => { |
| | self = this; |
| | menuItem.addEventListener('click', function (e) { |
| | e.preventDefault(); |
| | switch (index) { |
| | case 0: |
| | |
| | const fileInput = document.createElement('input'); |
| | fileInput.type = 'file'; |
| | fileInput.accept = 'image/*'; |
| |
|
| | |
| | fileInput.addEventListener('change', function (event) { |
| | const file = event.target.files[0]; |
| |
|
| | if (file) { |
| | const imageUrl = URL.createObjectURL(file); |
| | let img = new Image(); |
| | img.src = imageUrl; |
| | img.onload = () => self.handleImageLoad(img, file, null); |
| | } |
| | }); |
| |
|
| | fileInput.click(); |
| | |
| | self.node.contextMenu.style.display = 'none'; |
| | break; |
| | case 1: |
| | self.backgroundImage.visible(false).root.render(); |
| | self.node.properties.imgData = null; |
| | self.node.contextMenu.style.display = 'none'; |
| | break; |
| | } |
| | }); |
| | }); |
| | } |
| | } |
| |
|
| |
|
| | |
| | export function hideWidgetForGood(node, widget, suffix = '') { |
| | widget.origType = widget.type |
| | widget.origComputeSize = widget.computeSize |
| | widget.origSerializeValue = widget.serializeValue |
| | widget.computeSize = () => [0, -4] |
| | widget.type = "converted-widget" + suffix |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | if (widget.linkedWidgets) { |
| | for (const w of widget.linkedWidgets) { |
| | hideWidgetForGood(node, w, ':' + widget.name) |
| | } |
| | } |
| | } |