Comparing version
{ | ||
"name": "nflow-vis", | ||
"version": "0.1.11", | ||
"version": "0.1.12", | ||
"description": "d3 visualisation for nflow", | ||
@@ -21,5 +21,5 @@ "main": "dist/nflow-vis.js", | ||
"extract-text-webpack-plugin": "^0.9.1", | ||
"node-sass": "^3.4.2", | ||
"node-sass": "3.7.0", | ||
"raw-loader": "^0.5.1", | ||
"sass-loader": "^3.1.2", | ||
"sass-loader": "^4.0.0", | ||
"style-loader": "^0.13.0", | ||
@@ -26,0 +26,0 @@ "webpack": "^1.12.8", |
import './debug.scss' | ||
import d3 from 'd3' | ||
import nflow from 'nflow' | ||
@@ -33,17 +33,17 @@ import Parser from '../parser/parser' | ||
.html(tpl) | ||
d.d3tree = d.d3dom.select('.nflow-tree') | ||
d.d3timeline = d.d3dom.select('.nflow-timeline') | ||
d.d3inspector = d.d3dom.select('.nflow-inspector') | ||
var tree = flow.get('tree') | ||
tree.emit.downstream('dom', d.d3tree.node()) | ||
tree.emit.downstream('show-events', false) | ||
flow.get('timeline') | ||
.emit.downstream('dom', d.d3timeline.node()) | ||
flow.get('inspector') | ||
.emit.downstream('dom', d.d3inspector.node()) | ||
} | ||
@@ -64,3 +64,3 @@ | ||
.attr('height', h) | ||
d.d3timeline | ||
@@ -84,4 +84,4 @@ .attr('width', w) | ||
}) | ||
split(['.nflow-tree', '.nflow-timeline'], { | ||
@@ -98,3 +98,3 @@ direction: 'vertical', | ||
// var d3tree = d3.select('.nflow-tree') | ||
// vis && vis.dispose() | ||
@@ -108,6 +108,6 @@ // vis = nflowVis.Vis() | ||
// tree.emit.downstream('show-events', false) | ||
// timeline = nflowVis.Timeline(vis) | ||
// timeline.emit.downstream('dom', d3timeline.node()) | ||
} | ||
} |
@@ -11,3 +11,3 @@ import {RADIUS} from '../utils/paths' | ||
diagonal: d3.svg.diagonal() | ||
}) | ||
}) | ||
.on('dom' , dom) | ||
@@ -23,3 +23,3 @@ .on('update', render, updateRoutes) | ||
function render(){ | ||
let tree = this.target.parent() | ||
@@ -31,4 +31,4 @@ let flow = this.target | ||
let links = td.links.filter(link=>( | ||
!link.source.hidden | ||
&& !link.target.hidden | ||
!link.source.hidden | ||
&& !link.target.hidden | ||
)) | ||
@@ -62,2 +62,3 @@ // Update the links | ||
.classed('is-removed', d=>d.target.f.isUnparented) | ||
.classed('is-disposed', d=>d.target.f.isDisposed) | ||
.classed('is-cancelled', d=>utils.parentCancelled(d.target)) | ||
@@ -70,3 +71,3 @@ // Transition exiting nodes to the parent's new position. | ||
function updateRoutes(){ | ||
let tree = this.target.parent() | ||
@@ -78,7 +79,7 @@ let flow = this.target | ||
let links = td.links.filter(link=>( | ||
!link.source.hidden | ||
!link.source.hidden | ||
&& !link.target.hidden | ||
&& link.target.f.route | ||
)) | ||
var link = d3dom.selectAll(".routes") | ||
@@ -96,3 +97,3 @@ .data(links, function(d) { return d.target.f.guid; }); | ||
.classed('is-route', true) | ||
enter.append('path') | ||
@@ -103,3 +104,3 @@ .classed("link", true) | ||
.classed('is-route', true) | ||
link.attr('data-direction', d=>d.target.f.route) | ||
@@ -113,3 +114,3 @@ link.exit() | ||
let flow = this.target | ||
} | ||
@@ -158,3 +159,3 @@ | ||
// .filter(pair=>( | ||
// !pair.source.hidden | ||
// !pair.source.hidden | ||
// && !pair.target.hidden)) | ||
@@ -176,2 +177,2 @@ // return pairs | ||
}) | ||
} | ||
} |
@@ -10,3 +10,3 @@ import {RADIUS, CIRCLE, DROP} from '../utils/paths' | ||
dom: null, | ||
}) | ||
}) | ||
.on('dom' , dom) | ||
@@ -28,4 +28,4 @@ .on('update', render) | ||
return "translate(" + d.x0 + "," + d.y0 + ")"; }) | ||
.on("click", d=>flow.emit('select-node', d)) | ||
.on("mouseover", d=>flow.emit('select-node', d)) | ||
.on("mouseout", d=>flow.emit('select-node', null)) | ||
@@ -51,3 +51,3 @@ nodeEnter.append('path') | ||
}) | ||
//console.log('changedNodes', changedNodes.size()) | ||
@@ -68,7 +68,7 @@ var nodeUpdate = changedNodes | ||
}); | ||
changedNodes | ||
.select('path') | ||
.classed('is-flow', d=>d.f.isEvent) | ||
changedNodes | ||
@@ -81,3 +81,3 @@ .classed('is-cancelled', d=>d.f.status=='CANCELLED') | ||
.call(listeners) | ||
nodeUpdate | ||
@@ -116,2 +116,2 @@ .select("path") | ||
e.exit().remove() | ||
} | ||
} |
@@ -5,3 +5,6 @@ import {RADIUS, CIRCLE, DROP} from '../utils/paths' | ||
import './nodes.scss' | ||
export default (parent)=>( | ||
const DATA_RECT_SIZE = 9 | ||
export default (parent) => ( | ||
nflow.create('nodes') | ||
@@ -12,34 +15,33 @@ .parent(parent) | ||
diagonal: d3.svg.diagonal() | ||
}) | ||
.on('dom' , dom) | ||
}) | ||
.on('dom', dom) | ||
.on('update', render) | ||
) | ||
function dom(dom){ | ||
function dom (dom) { | ||
this.target.data().dom = dom | ||
} | ||
function render(){ | ||
function render () { | ||
let flow = this.target | ||
let tree = this.target.parent() | ||
let d = this.target.data() | ||
let td = tree.data() | ||
let d3dom = td.d3nodes | ||
if (!td.nodes) return; | ||
let nodes = td.nodes.filter(e=>!e.hidden) | ||
if (!td.nodes) return | ||
let nodes = td.nodes.filter(e => !e.hidden) | ||
// Update the nodes | ||
var node = d3dom.selectAll("g.node") | ||
.data(nodes, function(d) {return d.f.guid }) | ||
var nodeEnter = node.enter().append("g") | ||
.attr("class", "node") | ||
.style("opacity", 0) | ||
.attr("transform", function(d) { | ||
return "translate(" + d.x0 + "," + d.y0 + ")"; }) | ||
.on("click", d=>flow.emit('select-node', d.f)) | ||
var node = d3dom.selectAll('g.node') | ||
.data(nodes, function (d) { return d.f.guid }) | ||
var nodeEnter = node.enter().append('g') | ||
.attr('class', 'node') | ||
.style('opacity', 0) | ||
.attr('transform', function (d) { | ||
return 'translate(' + d.x0 + ',' + d.y0 + ')' | ||
}) | ||
.on('mouseover', d => flow.emit('select-node', d.f)) | ||
.on('mouseout', d => flow.emit('select-node', null)) | ||
nodeEnter.append('rect') | ||
@@ -49,5 +51,12 @@ .classed('text-bg', true) | ||
nodeEnter.append('path') | ||
.attr("transform", "scale(.8)") | ||
.attr("d", CIRCLE) | ||
.attr('transform', 'scale(.8)') | ||
.attr('d', CIRCLE) | ||
nodeEnter.append('rect') | ||
.classed('has-data', true) | ||
.attr('x', -DATA_RECT_SIZE / 2) | ||
.attr('y', -DATA_RECT_SIZE / 2) | ||
.attr('width', DATA_RECT_SIZE) | ||
.attr('height', DATA_RECT_SIZE) | ||
nodeEnter.append('g') | ||
@@ -57,34 +66,30 @@ .classed('listeners', true) | ||
nodeEnter | ||
//.append('g') | ||
//.attr("transform", `translate(${RADIUS+4},0)`) | ||
.append("text") | ||
// .append('g') | ||
// .attr("transform", `translate(${RADIUS+4},0)`) | ||
.append('text') | ||
.classed('node-label', true) | ||
.attr("x", 0) | ||
.attr("y", -(RADIUS+5)+'px') | ||
.attr("text-anchor", 'middle') | ||
//.attr("dy", ".35em") | ||
.style("fill-opacity", .1); | ||
.attr('x', 0) | ||
.attr('y', -(RADIUS + 5) + 'px') | ||
.attr('text-anchor', 'middle') | ||
// .attr("dy", ".35em") | ||
.style('fill-opacity', 0.1) | ||
var changedNodes = node | ||
.filter(d=>{ | ||
.filter(d => { | ||
return d.needsUpdate | ||
}) | ||
//console.log('changedNodes', changedNodes.size()) | ||
// console.log('changedNodes', changedNodes.size()) | ||
var nodeUpdate = changedNodes | ||
.transition() | ||
.delay(d=>d.updateIndex*td.delay) | ||
.style("opacity", 1) | ||
.delay(d => d.updateIndex * td.delay) | ||
.style('opacity', 1) | ||
.duration(td.duration) | ||
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) | ||
.each("end", function(d){ | ||
.attr('transform', function (d) { return 'translate(' + d.x + ',' + d.y + ')' }) | ||
.each('end', function (d) { | ||
d3.select(this) | ||
.select("text") | ||
.text(d=>d.displayName) | ||
.style("fill-opacity", 1) | ||
//.each(utils.wrapText(100)) | ||
.select('text') | ||
.text(d => d.displayName) | ||
.style('fill-opacity', 1) | ||
// .each(utils.wrapText(100)) | ||
.each(utils.fitText(70)) | ||
@@ -94,42 +99,47 @@ | ||
.select('.text-bg') | ||
.each(function(){ | ||
var text = d3.select(this.parentNode).select('text'); | ||
var bbox = text.node().getBBox(); | ||
var padding = {x:2,y:0}; | ||
.each(function () { | ||
var text = d3.select(this.parentNode).select('text') | ||
var bbox = text.node().getBBox() | ||
var padding = {x: 2, y: 0} | ||
var rect = d3.select(this) | ||
.attr("x", bbox.x - padding.x) | ||
.attr("y", bbox.y - padding.y) | ||
.attr("width", bbox.width + (padding.x*2)) | ||
.attr("height", bbox.height + (padding.y*2)) | ||
.attr('x', bbox.x - padding.x) | ||
.attr('y', bbox.y - padding.y) | ||
.attr('width', bbox.width + (padding.x * 2)) | ||
.attr('height', bbox.height + (padding.y * 2)) | ||
}) | ||
}); | ||
}) | ||
changedNodes | ||
.select('path') | ||
.classed('is-flow', d=>d.f.isEvent) | ||
.classed('is-flow', d => d.f.isEvent) | ||
changedNodes | ||
.classed('is-cancelled', d=>d.f.status=='CANCELLED') | ||
.classed('is-parent-cancelled', d=>utils.parentCancelled(d)) | ||
.classed('is-recipient', d=>d.f.recipientInfo) | ||
.classed('has-no-recipients', d=>utils.hasNoRecipients(d)) | ||
.classed('is-emitter', d=>d.f.isEmitter) | ||
.classed('is-cancelled', d => d.f.status == 'CANCELLED') | ||
.classed('is-disposed', d => d.f.isDisposed) | ||
.classed('is-parent-cancelled', d => utils.parentCancelled(d)) | ||
.classed('is-recipient', d => d.f.recipientInfo) | ||
.classed('has-no-recipients', d => utils.hasNoRecipients(d)) | ||
.classed('is-emitter', d => d.f.isEmitter) | ||
.call(listeners) | ||
nodeUpdate | ||
.select("path") | ||
.attr('d', d=>d.f.isEvent? DROP : CIRCLE) | ||
.select('path') | ||
.attr('d', d => d.f.isEvent ? DROP : CIRCLE) | ||
changedNodes | ||
.select('.has-data') | ||
.classed('is-hidden', d => d.f.data===undefined) | ||
.attr('y', d => d.f.isEvent ? 0 : -DATA_RECT_SIZE / 2) | ||
var nodeExit = node.exit() | ||
.remove(); | ||
.remove() | ||
} | ||
function listeners (sel) { | ||
const R = 2 | ||
function listeners(sel){ | ||
const R = 2; | ||
var e = sel | ||
.select('.listeners') | ||
.selectAll('.listener') | ||
.data(d=>Object.keys(d.f.listeners||{})) | ||
.data(d => Object.keys(d.f.listeners || {})) | ||
@@ -139,12 +149,12 @@ var l = e.enter() | ||
.classed('listener', true) | ||
.attr("transform", (d,i)=>( | ||
"translate(" + (RADIUS+R) + "," + (RADIUS+i*(R+.5)*2) + ")") | ||
.attr('transform', (d, i) => ( | ||
'translate(' + (RADIUS + R) + ',' + (RADIUS + i * (R + 0.5) * 2) + ')') | ||
) | ||
//TODO add tooltips | ||
//l.append('text') | ||
//.text(String) | ||
// TODO add tooltips | ||
// l.append('text') | ||
// .text(String) | ||
l.append('circle') | ||
.attr("r", R) | ||
.attr('r', R) | ||
.attr('title', String) | ||
@@ -154,2 +164,1 @@ | ||
} | ||
@@ -74,2 +74,21 @@ import nflow from 'nflow' | ||
actions.status = (s, f, newData, oldData)=>{ | ||
var e = s.nodeMap[f.guid] | ||
if (!e) return | ||
utils.updateHash(e) | ||
} | ||
actions.direction = (s, f, newData, oldData)=>{ | ||
var e = s.nodeMap[f.guid] | ||
if (!e) return | ||
utils.updateHash(e) | ||
} | ||
actions.dispose = (s, f, newData, oldData)=>{ | ||
var e = s.nodeMap[f.guid] | ||
if (!e) return | ||
e.isDisposed = true | ||
utils.updateHash(e) | ||
} | ||
actions.start = (s, f, newData, oldData)=>{ | ||
@@ -76,0 +95,0 @@ let e = createNode(newData,s) |
@@ -23,2 +23,3 @@ import './tree.scss' | ||
nodesize:{ width:100, height:80}, | ||
clonedNodes : {} | ||
@@ -79,2 +80,10 @@ }) | ||
fd.nodeMap = {} | ||
let minX = d3.min(fd.nodes, d=>d.x)-40 | ||
let maxX = d3.max(fd.nodes, d=>d.x)+40 | ||
let maxY = d3.max(fd.nodes, d=>d.y) | ||
fd.width = maxX-minX; | ||
fd.height = maxY; | ||
resizeSVG(fd) | ||
fd.nodes.forEach(function(d) { | ||
@@ -86,3 +95,3 @@ if (!fd.nodesByDepth[d.depth]) fd.nodesByDepth[d.depth] = [] | ||
//d.y = d.depth * (root.hidden?40:fd.nodesize.height)+ (root.hidden?0:fd.nodesize.height); | ||
d.x+=fd.width/2 | ||
d.x-=minX//fd.width/2 | ||
d.y-=fd.nodesize.height>>1 | ||
@@ -152,10 +161,4 @@ | ||
)) | ||
} | ||
function cloneNode(e,d){ | ||
@@ -167,3 +170,2 @@ if (!d.clonedNodes[e.guid]) | ||
function init(){ | ||
@@ -182,3 +184,2 @@ let d = this.target.data() | ||
d.zoom = d3.behavior.zoom() | ||
@@ -253,12 +254,22 @@ .scaleExtent([.1,2]) | ||
function fitContents(){ | ||
function fitContents(){} | ||
} | ||
function render(){ | ||
let d = this.target.data() | ||
setTimeout(()=>{ | ||
this.emit('updated') | ||
}, d.duration + 1) | ||
// d.d3links | ||
// .selectAll('.link') | ||
// .data(d.links) | ||
} | ||
function resizeSVG(d){ | ||
d.d3svg | ||
.attr("width", d.width) | ||
.attr("height", d.height); | ||
d.d3overlay | ||
.attr("width", d.width) | ||
.attr("height", d.height); | ||
} | ||
@@ -269,16 +280,18 @@ | ||
let d3dom = d3.select(d.dom) | ||
d.width = d.isSVG | ||
let w = d.isSVG | ||
? parseInt(d3dom.attr('width')) | ||
: parseInt(d3dom.style('width')) | ||
d.height = d.isSVG | ||
let h = d.isSVG | ||
? parseInt(d3dom.attr('height')) | ||
: parseInt(d3dom.style('height')) | ||
w = w^0 | ||
h = h^0 | ||
if (d.width === w && d.height === h ) { | ||
this.stopPropagation() | ||
return | ||
} | ||
d.width = w; | ||
d.height = h; | ||
d.d3svg | ||
.attr("width", d.width) | ||
.attr("height", d.height); | ||
d.d3overlay | ||
.attr("width", d.width) | ||
.attr("height", d.height); | ||
resizeSVG(d) | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
2640051
54.13%29679
62.96%