UNPKG

rpd

Version:

RPD is a minimal framework for building Node-Based User Interfaces, powered by Reactive Programming

173 lines (136 loc) 5.79 kB
;(function(global) { "use strict"; var Rpd = global.Rpd; if (typeof Rpd === "undefined" && typeof require !== "undefined") { Rpd = require('rpd'); } Rpd.style('webpd', 'svg', (function() { var socketPadding = 10; // distance between inlets/outlets in SVG units var nodeHeight = 18; var connectorWidth = 7; function _createSvgElement(name) { return document.createElementNS(d3.namespaces.svg, name); } function getPos(elm) { var bounds = elm.getBoundingClientRect(); return { x: bounds.left, y: bounds.top } }; return function(config) { var lastCanvas; var nodeToProcessElm = {}; var nodeToInlets = {}, nodeToOutlets = {}; var inletToElm = {}, outletToElm = {}; function redistributeInlets(node) { var inlets = nodeToInlets[node.id]; var inlet_count = inlets.length; if (inlet_count <= 1) return; var bodyWidth = nodeToProcessElm[node.id].node().getBBox().width; inlets.forEach(function(inlet, idx) { var xPos = idx * (bodyWidth / (inlet_count - 1)) - idx * (connectorWidth / (inlet_count - 1)); inletToElm[inlet.id].attr('transform', 'translate(' + xPos + ',0)'); }); } function redistributeOutlets(node) { var outlets = nodeToOutlets[node.id]; var outlet_count = outlets.length; if (outlet_count <= 1) return; var bodyWidth = nodeToProcessElm[node.id].node().getBBox().width; outlets.forEach(function(outlet, idx) { var xPos = idx * (bodyWidth / (outlet_count - 1)) - idx * (connectorWidth / (outlet_count - 1)); outletToElm[outlet.id].attr('transform', 'translate(' + xPos + ',0)'); }); } return { createCanvas: function(patch, parent) { return { element: d3.select(_createSvgElement('g')) .classed('rpd-patch', true).node() }; }, createNode: function(node, render, description, icon) { var size = render.size ? { width: render.size.width || 50, height: render.size.height || 18 } : { width: 18, height: 18 }; var nodeElm = d3.select(_createSvgElement('g')) .attr('class', 'rpd-node'); nodeElm.classed('rpd-'+node.type.slice(0, node.type.indexOf('/'))+'-toolkit-node', true) .classed('rpd-'+node.type.replace('/','-'), true); var isPdNode = (node.type.indexOf('wpd/') === 0); if (!isPdNode) { nodeElm.append('rect').classed('rpd-background').classed('rpd-drag-handle', true) .attr('width', size.width).attr('height', size.height); } nodeElm.append('g').classed('rpd-process', true).classed('rpd-drag-handle', isPdNode); nodeElm.append('g').classed('rpd-inlets', true); nodeElm.append('g').classed('rpd-outlets', true) .attr('transform', 'translate(0,' + (nodeHeight - 2) + ')'); nodeToProcessElm[node.id] = nodeElm.select('.rpd-process'); nodeToInlets[node.id] = []; nodeToOutlets[node.id] = []; return { element: nodeElm.node(), size: size }; }, createInlet: function(inlet, render) { var inletElm = d3.select(_createSvgElement('g')).attr('class', 'rpd-inlet'); inletElm.append('g').attr('class', 'rpd-connector') .append('rect').attr('width', 7).attr('height', 2); inletToElm[inlet.id] = inletElm; nodeToInlets[inlet.node.id].push(inlet); redistributeInlets(inlet.node); return { element: inletElm.node() }; }, createOutlet: function(outlet, render) { var outletElm = d3.select(_createSvgElement('g')).attr('class', 'rpd-outlet'); outletElm.append('g').attr('class', 'rpd-connector') .append('rect').attr('width', 7).attr('height', 2); outletToElm[outlet.id] = outletElm; nodeToOutlets[outlet.node.id].push(outlet); redistributeOutlets(outlet.node); return { element: outletElm.node() }; }, createLink: function(link) { var linkElm = d3.select(_createSvgElement('line')) .attr('class', 'rpd-link'); return { element: linkElm.node(), rotate: function(x0, y0, x1, y1) { linkElm.attr('x1', x0).attr('y1', y0) .attr('x2', x1).attr('y2', y1); }, noPointerEvents: function() { linkElm.style('pointer-events', 'none'); } }; }, getInletPos: function(inlet) { var connectorPos = getPos(inletToElm[inlet.id].select('.rpd-connector').node()); return { x: connectorPos.x + 3, y: connectorPos.y + 1 }; }, getOutletPos: function(outlet) { var connectorPos = getPos(outletToElm[outlet.id].select('.rpd-connector').node()); return { x: connectorPos.x + 3, y: connectorPos.y + 1 }; }, getLocalPos: function(pos) { if (!lastCanvas) return pos; // calculate once on patch switch? var canvasPos = getPos(lastCanvas.node()); return { x: pos.x - canvasPos.x, y: pos.y - canvasPos.y }; }, onPatchSwitch: function(patch, canvas) { lastCanvas = d3.select(canvas); }, onInletRemove: function(inlet) { var nodeId = inlet.node.id; nodeToInlets[nodeId] = nodeToInlets[nodeId].filter(function(other) { return other.id !== inlet.id; }); }, onOutletRemove: function(outlet) { var nodeId = outlet.node.id; nodeToOutlets[nodeId] = nodeToOutlets[nodeId].filter(function(other) { return other.id !== outlet.id; }); } }; } })()); })(this);