image-nodes
Version:
A library for visual programming of image-processing algorithms on dicom images
217 lines (180 loc) • 5.22 kB
JavaScript
import ContextMenu from './context-menu.js';
import Dropdown from './dropdown.js';
import { event, line, mouse } from 'd3';
import ImageMath from "./image-math.js";
import Link from './link.js';
import Links from './links.js';
import NodeActions from './node-actions.js';
import NodeDropdown from './node-dropdown.js';
import Nodes from './nodes.js';
import Port from './port.js';
import Ports from './ports.js';
import ImageNode from './node-image.js';
class Node {
constructor(svg, props) {
this.svg = svg;
this.x = props.x;
this.y = props.y;
this.width = props.width || 140;
this.height = props.height || 140;
this.title = props.title;
this.input = props.input;
this.output = props.output;
this.inputport = null;
this.outputport = null;
this.file = null;
this.img = null;
this.isDragged = false;
this.creatingLink = false;
this.portCount = 0;
this.id = 'node-' + Nodes.nodes.length;
this.createNode();
Nodes.addNode(this);
}
createNode(svg) {
this.svg = svg || this.svg;
this.g = this.svg.append("g");
this.g.attr("transform", "translate(" + this.x + "," + this.y + ")")
.attr("class", this.id)
this.createNodeBox();
this.createTitle();
this.createGrip();
this.createNodeDelete();
this.inputport = this.input.map((item, index) => {
return this.createNodeInput(item, index);
})
this.outputport = this.output.map((item, index) => {
return this.createNodeOutput(item, index);
})
}
createNodeBox() {
var box = this.g.append("rect")
.attr("x", 0).attr("y", 0)
.attr("width", this.width).attr("height", this.height)
.attr("rx", 6).attr("ry", 6)
.attr("fill", '#F7F7F7')
.style("filter", "url(#drop-shadow)")
.on("contextmenu", () => {
var m = mouse(this.svg.node());
var removeNode = Nodes.removeNode.bind(Nodes, this);
ContextMenu.create(this.svg, m[0], m[1], removeNode);
})
if(this.title == 'Image') {
new NodeDropdown(this);
box.on("dragover", this.nodeDragOver.bind(this));
box.on("drop", this.nodeDrop.bind(this));
}
else if(this.title == 'Fit') {
new Dropdown(this, ['Linear Map', 'Nonlinear Map']);
}
}
createNodeDelete() {
var b = this.g.append('rect')
.attr("x", this.width - 20).attr("y", 12)
.attr("width", 10).attr("height", 10)
.attr("fill", "#757575")
.attr("opacity", 0)
var d = this.g.append('text')
.attr("x", this.width - 20).attr("y", 22)
.attr("fill", "#757575")
.text('x')
b.on('mouseover', () => { d.attr("fill", "red"); });
b.on('mouseleave', () => { d.attr("fill", "#757575"); });
b.on('click', () => { Nodes.removeNode(this); })
}
removeNode() {
this.g.remove();
}
nodeDragOver() {
event.stopPropagation();
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}
nodeDrop() {
event.stopPropagation();
event.preventDefault();
Nodes.setActiveNode(this);
ImageNode.readFile(event);
}
createTitle() {
this.g.append('text')
.attr("x", this.width / 2).attr("y", 16)
.attr("fill", "#222222")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.style("font-size", "18px")
.text(this.title)
}
createGrip() {
var gripX = 10, gripY = 10;
var grip = this.g.append("g");
grip.attr("transform", "translate(" + gripX + "," + gripY + ")");
var pos = [[4,4], [10,4], [4,10], [10,10]];
pos.forEach((p)=> {
grip.append('circle')
.attr('cx', p[0])
.attr('cy', p[1])
.attr('r', 2)
.attr('fill', '#222222')
.attr('opacity', 0.5)
})
var grab = grip.append("rect")
.attr("x", 0).attr("y", 0)
.attr("width", 14).attr("height", 14)
.attr("fill", '#222222')
.attr("opacity", 0)
.attr("class", "grab")
var grab2 = grip.append("rect")
.attr("x", 40).attr("y", 0)
.attr("width", 40).attr("height", 14)
.attr("fill", '#222222')
.attr("opacity", 0)
.attr("class", "grab")
var mousedownHandler = () => {
this.isDragged = true;
this.mouse = mouse(grab.node());
this.svg.on("mousemove", () => {
if(this.isDragged) {
var m = mouse(this.svg.node());
this.x = (m[0] - this.mouse[0] - gripX);
this.y = (m[1] - this.mouse[1] - gripY);
this.g.attr("transform", "translate(" + this.x + "," + this.y + ")");
Links.update();
}
})
// Deactivate Node drag
this.svg.on("mouseup", () => {
this.isDragged = false;
})
event.preventDefault();
}
// Activate Node drag
grab.on("mousedown", mousedownHandler);
grab2.on("mousedown", mousedownHandler);
}
createNodeInput(input, index) {
input = new Port(input, index);
input.createInputPort(this, index);
return input;
}
createNodeOutput(output, index) {
output = new Port(output, index);
output.createOutputPort(this, index);
return output;
}
createImg(imgsrc) {
this.svg.selectAll('.' + this.id)
.append('image')
.attr("xlink:href", imgsrc)
.attr('x', this.width / 2 - 40 / 2)
.attr('y', 40)
.attr('width', 40)
}
getInputNode(index) {
return this.input[index].link.getInputNode();
}
runNode() {
return NodeActions.runAction(this.title.toLowerCase(), { node:this });
}
}
export default Node;