|
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}`
|
|
|
|
|
|
const fakeimagewidget = this.addWidget("COMBO", "image", null, () => { }, {});
|
|
hideWidgetForGood(this, fakeimagewidget)
|
|
|
|
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 () {
|
|
this.editor = new PointsEditor(this);
|
|
});
|
|
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.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)
|
|
}
|
|
}
|
|
} |