Skip to content

Instantly share code, notes, and snippets.

@billdwhite
Created March 31, 2014 19:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save billdwhite/9900551 to your computer and use it in GitHub Desktop.
Save billdwhite/9900551 to your computer and use it in GitHub Desktop.
d3 Multi Flow Container Demo
d3.demo = {};
d3.demo.currentScale = 1;
d3.demo.app = function() {
"use strict";
var width = 600,
height = 900,
margin = {top: 0, right: 0, bottom: 0, left: 0},
base = null,
shapes = [],
wrapperBorder = 2,
canvas = null;
function app(selection) {
base = selection;
var svg = selection.append("svg")
.attr("class", "svg demo")
.style("shape-rendering", "auto") // shapeRendering options; [crispEdges|geometricPrecision|optimizeSpeed|auto]
.style("text-rendering", "auto") // textRendering options; [optimizeLegibility|geometricPrecision|optimizeSpeed|auto]
.style("color-rendering", "auto") // colorRendering options; [optimizeQuality|optimizeSpeed|auto]
.attr("width", width + (wrapperBorder*2))
.attr("height", height + (wrapperBorder*2));
var svgDefs = svg.append("defs");
// clip path
svgDefs.append("clipPath")
.attr("id", "wrapperClipPath")
.attr("class", "clipPath")
.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
// minimap drop shadow
var shapeDropShadow = svgDefs.append("svg:filter")
.attr("id", "shapeDropShadow")
.attr("x", "-20%")
.attr("y", "-20%")
.attr("width", "140%")
.attr("height", "140%");
shapeDropShadow.append("svg:feOffset")
.attr("result", "offOut")
.attr("in", "SourceGraphic")
.attr("dx", "1")
.attr("dy", "1");
shapeDropShadow.append("svg:feColorMatrix")
.attr("result", "matrixOut")
.attr("in", "offOut")
.attr("type", "matrix")
.attr("values", "0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.5 0");
shapeDropShadow.append("svg:feGaussianBlur")
.attr("result", "blurOut")
.attr("in", "matrixOut")
.attr("stdDeviation", "3");
shapeDropShadow.append("svg:feBlend")
.attr("in", "SourceGraphic")
.attr("in2", "blurOut")
.attr("mode", "normal");
var insetShadowFilter = svgDefs.append("svg:filter")
.attr("id", "insetShadowFilter");
insetShadowFilter.append("svg:feOffset")
.attr("dx", "0")
.attr("dy", "0");
insetShadowFilter.append("svg:feGaussianBlur")
.attr("stdDeviation", "5")
.attr("result", "offsetBlur");
insetShadowFilter.append("svg:feComposite")
.attr("operator", "out")
.attr("in", "SourceGraphic")
.attr("in2", "offsetBlur")
.attr("result", "inverse");
insetShadowFilter.append("svg:feFlood")
.attr("flood-color", "black")
.attr("flood-opacity", ".5")
.attr("result", "color");
insetShadowFilter.append("svg:feComposite")
.attr("operator", "in")
.attr("in", "color")
.attr("in2", "inverse")
.attr("result", "shadow");
insetShadowFilter.append("svg:feComposite")
.attr("operator", "over")
.attr("in", "shadow")
.attr("in2", "SourceGraphic");
var outerWrapper = svg.append("g")
.attr("class", "wrapper outer");
outerWrapper.append("rect")
.attr("class", "background")
.attr("rx", "6")
.attr("ry", "6")
.attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2);
var innerWrapper = outerWrapper.append("g")
.attr("class", "wrapper inner")
.attr("clip-path", "url(#wrapperClipPath)")
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")");
innerWrapper.append("rect")
.attr("class", "background")
.attr("rx", "6")
.attr("ry", "6")
.attr("width", width)
.attr("height", height);
canvas = innerWrapper.append("g")
.attr("class", "canvas")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(0,0)");
canvas.append("rect")
.attr("class", "background")
.attr("rx", "6")
.attr("ry", "6")
.attr("width", width)
.attr("height", height);
var shapesGroup = canvas.append("g")
.attr("class", "shapes")
.attr("transform", "translate(" + (-wrapperBorder) + "," + (-wrapperBorder) + ")");
function getMousePoint(context) {
var p = d3.mouse(context),
t = d3.demo.util.getXYFromTranslate(canvas.attr("transform"));
p[0] = (p[0] - t[0]);
p[1] = (p[1] - t[1]);
return p;
}
// DRAG SELECTION HANDLERS
svg.on({
mousedown: function() {
if (d3.event.target === canvas.select(".background").node()) {
shapes.forEach(function(shape) { // clear existing selections
shape.selected(false).render();
});
var p = getMousePoint(this);
this.selectionAnchorPoint = p;
canvas.append("rect")
.attr({
rx: 4,
ry: 4,
class: "selection",
x: p[0],
y: p[1],
width: 0,
height: 0
});
}
},
mousemove: function() {
var selectionRectangle = canvas.select("rect.selection");
if (!selectionRectangle.empty()) {
var mp = getMousePoint(this),
ap = this.selectionAnchorPoint,
d = {x:0, y:0, width:0, height:0};
// horizontal selection sizing
if (mp[0] < ap[0]) {
d.x = mp[0];
d.width = ap[0] - mp[0];
} else {
d.x = ap[0];
d.width = mp[0] - ap[0];
}
// vertical selection sizing
if (mp[1] < ap[1]) {
d.y = mp[1];
d.height = ap[1] - mp[1];
} else {
d.y = ap[1];
d.height = mp[1] - ap[1];
}
selectionRectangle.attr(d);
shapes.forEach(function(shape) {
var p1 = {x:shape.x(), y:shape.y()},
p2 = {x:shape.x() + shape.width() ,y:shape.y() + shape.height()},
p3 = {x:d.x, y:d.y},
p4 = {x:d.x + d.width,y:d.y + d.height};
shape.selected(!(p2.y < p3.y || p1.y > p4.y || p2.x < p3.x || p1.x > p4.x)).render();
});
}
},
mouseup: function() {
canvas.selectAll("rect.selection").remove(); // remove selection frame
},
mouseout: function() {
if (!d3.event.relatedTarget || d3.event.relatedTarget.tagName == 'HTML') {
canvas.selectAll("rect.selection").remove(); // remove selection frame
}
}
});
// SELECTION DRAGGING HANDLERS
function handleShapeDragStart(event) {
shapes.forEach(function(shape) {
if (shape.selected() && shape.uuid() != event.shape.uuid()) {
shape.slaveDragStart();
}
});
}
function handleShapeDrag(event) {
shapes.forEach(function(shape) {
if (shape.selected() && shape.uuid() != event.shape.uuid()) {
shape.slaveDrag();
}
});
}
function handleShapeDragEnd(event) {
shapes.forEach(function(shape) {
if (shape.selected() && shape.uuid() != event.shape.uuid()) {
shape.slaveDragEnd();
}
});
}
/** ADD SHAPE **/
demo.addShape = function(shape) {
shapes.push(shape);
shapesGroup.call(shape);
shape.on("shapeDragStart", handleShapeDragStart); // selection drag handler
shape.on("shapeDrag", handleShapeDrag); // selection drag handler
shape.on("shapeDragEnd", handleShapeDragEnd); // selection drag handler
};
/** RENDER **/
demo.render = function() {
svgDefs
.select(".clipPath .background")
.attr("width", width)
.attr("height", height);
svg
.attr("width", width + (wrapperBorder*2))
.attr("height", height + (wrapperBorder*2));
outerWrapper
.select(".background")
.attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2);
innerWrapper
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")")
.select(".background")
.attr("width", width)
.attr("height", height);
canvas
.attr("width", width)
.attr("height", height)
.select(".background")
.attr("width", width)
.attr("height", height);
};
return demo;
}
//============================================================
// Accessors
//============================================================
app.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
width = width - margin.left - margin.right;
return this;
};
app.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
height - margin.top - margin.bottom;
return this;
};
return app;
};
d3.demo.container = function() {
"use strict";
var shape = d3.demo.shape(),
children = [],
flowbox = null;
function container(selection) {
shape.call(shape, selection);
d3.select(shape.node).classed("container", true);
flowbox = d3.demo.flowbox().shape(shape).x(5).y(30);
d3.select(shape.node).call(flowbox);
container.node = shape.node;
container.render = function() {
flowbox.children(children).render();
setTimeout(shape.render, 250); // give flow time to run before rendering
};
container.render();
}
container.children = function(value) {
if (!arguments.length) { return children; }
children = value;
return this;
};
return d3_shape_rebind(container, shape);
};
d3.demo.flowbox = function() {
"use strict";
var x = 0,
y = 0,
layout = d3.demo.layout.flow(),
shape = null,
base = null,
uuid = d3.demo.util.uuid(),
children = [];
var dispatch = d3.dispatch(
"flowboxMouseOver",
"flowboxMouseOut",
"flowboxMouseUp");
function flowbox(selection) {
base = selection;
layout.nodeWidth(75).nodeHeight(24);
selection.each(function(d, i) {
var parent = d3.select(this);
var container = parent.append("g")
.classed("flowbox", "true")
.attr("transform", "translate(" + x + "," + y + ")")
.attr("clip-path", "url(#clippath" + uuid + ")");
container.append("rect")
.classed("background", true);
flowbox.node = container.node();
var clipPath = d3.select("svg defs")
.append("clipPath")
.attr("class", "clippath")
.attr("id", "clippath" + uuid);
clipPath.append("rect")
.attr("class", "background")
.attr("width", shape.width() - (flowbox.x() * 2))
.attr("height", shape.height() - (flowbox.y() + flowbox.x()));
flowbox.render = function() {
container
.select(".background")
.attr("width", shape.width() - (flowbox.x() * 2))
.attr("height", shape.height() - (flowbox.y() + flowbox.x()));
clipPath
.attr("width", shape.width() - (flowbox.x() * 2))
.attr("height", shape.height() - (flowbox.y() + flowbox.x()))
.select(".background")
.attr("width", shape.width() - (flowbox.x() * 2))
.attr("height", shape.height() - (flowbox.y() + flowbox.x()));
layout.width(shape.width());
var nodes = layout(children);
var node = container.selectAll("g.node")
.data(nodes[0], function(d) { return d.id || (d.id = ++i); });
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.style("opacity", 1e-6);
nodeEnter.append("svg:rect")
.attr("class", "background")
.attr("rx", "4")
.attr("ry", "4")
.attr("height", function(d) { return d.height; })
.attr("width", function(d) { return d.width; });
nodeEnter.append("svg:text")
.attr("class", "label nodelabel")
.attr("transform", "translate(5, 15)")
.text(function(d) { return d.name; });
// Transition nodes to their new position.
nodeEnter.transition()
.duration(300)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style("opacity", 1);
var nodeUpdate = node.transition()
.duration(300);
nodeUpdate.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style("opacity", 1)
.select("rect");
nodeUpdate.select(".background")
.attr("height", function(d) { return d.height; })
.attr("width", function(d) { return d.width; });
// Transition exiting nodes to the parent's new position.
node.exit().transition()
.duration(300)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style("opacity", 1e-6)
.remove();
};
flowbox.render();
shape.on("shapeUpdated.container", flowbox.render); // render when shape changes size/shape, etc
});
}
flowbox.children = function(value) {
if (!arguments.length) { return children; }
children = value;
flowbox.render();
return this;
};
flowbox.shape = function(value) {
if (!arguments.length) { return r; }
shape = value;
return this;
};
flowbox.x = function(value) {
if (!arguments.length) { return x; }
x = parseInt(value, 10);
return this;
};
flowbox.y = function(value) {
if (!arguments.length) { return y; }
y = parseInt(value, 10);
return this;
};
d3.rebind(flowbox, dispatch, "on");
return flowbox;
};
d3.demo.handle = function() {
"use strict";
var width = 8,
height = 20,
x = 0,
y = 0,
type = null,
base = null;
var dispatch = d3.dispatch(
"handleMouseover",
"handleMouseout",
"handleDragStart",
"handleDrag",
"handleDragEnd");
function handle(selection, evented) {
base = selection;
evented.on("shapeResize", function() {
//log("handle: shapeResize()");
});
selection.each(function(d, i) {
var parent = d3.select(this);
var container = parent.append("g")
.attr("class", "handle")
.attr("transform", "translate(" + x + "," + y + ")");
handle.node = container.node();
var background = container.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("mouseover", function(event) {
d3.select(this).classed("hover", true);
dispatch.handleMouseover({
handle: this,
pos: [d3.event.x, d3.event.y]
});
})
.on("mouseout", function(event) {
d3.select(this).classed("hover", false);
dispatch.handleMouseout({
handle: this,
pos: [d3.event.x, d3.event.y]
});
});
switch(type) {
case handle.TYPE_TOP:
case handle.TYPE_BOTTOM:
background.classed("vertical", true);
break;
case handle.TYPE_LEFT:
case handle.TYPE_RIGHT:
background.classed("horizontal", true);
break;
default:
break;
}
var drag = d3.behavior.drag()
.origin(Object)
.on("dragstart", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
container.classed("dragging", true);
dispatch.handleDragStart({
handle: this,
pos: [d3.event.x, d3.event.y]
});
})
.on("drag", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
var selection = d3.select(this);
switch(type) {
case handle.TYPE_TOP:
y += d3.event.dy;
break;
case handle.TYPE_BOTTOM:
y += d3.event.dy;
break;
case handle.TYPE_LEFT:
x += d3.event.dx;
break;
case handle.TYPE_RIGHT:
x += d3.event.dx;
break;
default:
break;
}
container.attr("transform", "translate(" + x + "," + y + ")");
dispatch.handleDrag({
handle: this,
pos: [d3.event.x, d3.event.y]
});
})
.on("dragend", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
dispatch.handleDragEnd({
handle: this,
pos: [d3.event.x, d3.event.y]
});
container.classed("dragging", false);
});
container.call(drag);
handle.render = function() {
container.attr("transform", "translate(" + x + "," + y + ")");
};
container.call(drag);
});
}
handle.x = function(value) {
if (!arguments.length) return x;
x = parseInt(value, 10);
return this;
};
handle.y = function(value) {
if (!arguments.length) return y;
y = parseInt(value, 10);
return this;
};
handle.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
return this;
};
handle.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
};
handle.type = function(value) {
if (!arguments.length) return type;
type = value;
return this;
};
handle.TYPE_RIGHT = "right";
handle.TYPE_LEFT = "left";
handle.TYPE_TOP = "top";
handle.TYPE_BOTTOM = "bottom";
d3.rebind(handle, dispatch, "on");
return handle;
};
d3.demo.layout = {};
d3.demo.layout.flow = function() {
var hierarchy = d3.layout.hierarchy().sort(null).value(null),
nodeWidth = 75,
nodeHeight = 50,
containerHeight = 20,
width = 0,
height = 0,
padding = {top:10, left:10, bottom:10, right:10},
margin = {top:10, left:10, bottom:10, right:10};
function flow(d, i) {
var nodes = hierarchy.call(this, d, i),
root = nodes[0];
function firstWalk(node) {
var children = node.children ? node.children : node.length>0 ? node : null;
if (children && children.length > 0) {
var n = children.length,
i = -1,
child;
while (++i < n) {
child = children[i];
firstWalk(child);
}
gridLayout(node, children, node.depth);
} else {
node.width = node._children ? width - (node.depth * (padding.left + padding.right)) - (padding.left + padding.right) : nodeWidth;
node.height = node._children ? containerHeight : nodeHeight;
}
}
function secondWalk(node) {
var children = node.children;
if (children && children.length > 0) {
var i = -1,
n = children.length,
child;
while (++i < n) {
child = children[i];
child.x += node.x;
child.y += node.y;
secondWalk(child);
}
}
}
function gridLayout(node, children, depth) {
var paddingValue = node.parent ? padding.left + padding.right : margin.left + margin.right;
var availableWidth = width - (depth * (paddingValue)) - (paddingValue),
currentX = padding.left,
currentY = padding.top,
tallestChildHeight = 0;
children.forEach(function(child) {
if ((currentX + child.width + padding.right) >= availableWidth) {
currentX = padding.right;
currentY += tallestChildHeight;
tallestChildHeight = 0;
}
child.x = currentX;
child.y = currentY;
currentX += child.width + padding.right;
tallestChildHeight = Math.max(tallestChildHeight, child.height + padding.bottom);
});
node.width = availableWidth;
node.height = currentY + tallestChildHeight;
node.x = node.parent ? padding.left : margin.left;
node.y = node.parent ? padding.top : margin.top;
}
firstWalk(root);
secondWalk(root);
height = root.height;
return nodes;
}
flow.margin = function(_) {
if (!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
return this;
};
flow.padding = function(_) {
if (!arguments.length) return padding;
padding.top = typeof _.top != 'undefined' ? _.top : padding.top;
padding.right = typeof _.right != 'undefined' ? _.right : padding.right;
padding.bottom = typeof _.bottom != 'undefined' ? _.bottom : padding.bottom;
padding.left = typeof _.left != 'undefined' ? _.left : padding.left;
return this;
};
flow.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value);
return this;
};
flow.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value);
return this;
};
flow.nodeWidth = function(value) {
if (!arguments.length) return nodeWidth;
nodeWidth = parseInt(value);
return this;
};
flow.nodeHeight = function(value) {
if (!arguments.length) return nodeHeight;
nodeHeight = parseInt(value);
return this;
};
flow.containerHeight = function(value) {
if (!arguments.length) return containerHeight;
containerHeight = parseInt(value);
return this;
};
return flow;
};
d3.demo.shape = function() {
"use strict";
var width = 150,
height = 100,
x = 0,
y = 0,
label = "",
selected = false,
base = null,
uuid = d3.demo.util.uuid();
var dispatch = d3.dispatch(
"shapeDragStart",
"shapeDrag",
"shapeDragEnd",
"shapeResize",
"shapeUpdated");
function shape(selection) {
base = selection;
selection.each(function(d, i) {
var parent = d3.select(this);
var container = parent.append("g")
.attr("class", "shape")
.attr("transform", "translate(" + x + "," + y + ")");
shape.node = container.node();
var background = container.append("rect")
.attr("class", "background")
.attr("filter", "url('#shapeDropShadow')")
.attr("width", width)
.attr("height", height)
.attr("rx", "4")
.attr("ry", "4");
var labelText = container.append("text")
.attr("class", "label")
.attr("transform", "translate(5, 20)")
.text(label);
// HANDLES
var rightHandle = d3.demo.handle();
rightHandle
.x(width - rightHandle.width()/2)
.y(height/2 - rightHandle.height()/2)
.type(rightHandle.TYPE_RIGHT)
.on("handleDrag", function(event) {
width += d3.event.dx;
shape.render();
dispatch.shapeUpdated({
this: container,
shape: shape
});
})
.on("handleDragEnd", function(event) {
dispatch.shapeUpdated({
this: container,
shape: shape
});
});
container.call(rightHandle, shape);
var drag = d3.behavior.drag()
.on("dragstart", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
d3.demo.util.bringToFront(container.node());
dispatch.shapeDragStart({
shape: shape,
pos: [d3.event.x, d3.event.y]
});
})
.on("drag", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
background.classed("dragging", true);
dispatch.shapeDrag({
shape: shape,
pos: [d3.event.x, d3.event.y]
});
x += d3.event.dx;
y += d3.event.dy;
shape.render();
})
.on("dragend", function(d) {
d3.event.sourceEvent.stopImmediatePropagation();
background.classed("dragging", false);
dispatch.shapeDragEnd({
shape: shape,
pos: [d3.event.x, d3.event.y]
});
});
container.call(drag);
shape.render = function() {
container.attr("transform", "translate(" + x + "," + y + ")")
.attr("width", width)
.attr("height", height)
.classed("selected", selected)
.select(".background")
.attr("width", width)
.attr("height", height);
dispatch.shapeUpdated({
this: container,
shape: this
});
labelText.text(label);
rightHandle.x(width - rightHandle.width()/2).y(height/2 - rightHandle.height()/2).render();
};
});
}
shape.x = function(value) {
if (!arguments.length) { return x; }
x = parseInt(value, 10);
return this;
};
shape.y = function(value) {
if (!arguments.length) { return y; }
y = parseInt(value, 10);
return this;
};
shape.width = function(value) {
if (!arguments.length) { return width; }
width = parseInt(value, 10);
if (shape.render) { shape.render(); }
return this;
};
shape.height = function(value) {
if (!arguments.length) { return height; }
height = parseInt(value, 10);
if (shape.render) { shape.render(); }
return this;
};
shape.label = function(value) {
if (!arguments.length) { return label; }
label = value;
return this;
};
shape.selected = function(value) {
if (!arguments.length) { return selected; }
selected = value;
return this;
};
shape.slaveDragStart = function() {
d3.select(this.node).select(".background").classed("dragging", true);
};
shape.slaveDrag = function() {
x += d3.event.dx;
y += d3.event.dy;
shape.render();
};
shape.slaveDragEnd = function() {
d3.select(this.node).select(".background").classed("dragging", false);
};
shape.uuid = function(value) {
if (!arguments.length) { return uuid; }
uuid = value;
return this;
};
d3.rebind(shape, dispatch, "on");
return shape;
};
// A method assignment helper for hierarchy subclasses.
function d3_shape_rebind(object, hierarchy) {
d3.rebind(object, hierarchy, "render", "x", "y", "width", "height", "label", "selected", "slaveDragStart", "slaveDrag", "slaveDragEnd", "uuid", "on");
return object;
}
d3.demo.util = {};
d3.demo.util.bringToFront = function(element) {
element.parentNode.appendChild(element);
};
d3.demo.util.getXYFromTranslate = function(translateString) {
var split = translateString.split(",");
var x = split[0] ? ~~split[0].split("(")[1] : 0;
var y = split[1] ? ~~split[1].split(")")[0] : 0;
return [x, y];
};
d3.demo.util.getXYFromTranslateOnNode = function(element) {
return d3.demo.util.getXYFromTranslate(element.getAttribute("transform"));
};
d3.demo.util.makePoint = function(element, sourceElement, xy) {
var p = element.nearestViewportElement.createSVGPoint();
var matrix = element.getTransformToElement(sourceElement.nearestViewportElement);
//matrix.scale(d3.demo.scale);
matrix.scale(1);
p.x = xy[0];
p.y = xy[1];
var sp = p.matrixTransform(matrix);
return sp;
};
d3.demo.util.getScreenCoords = function(x, y, translate, scale) {
var xn = (x - translate[0]) / scale;
var yn = (y - translate[1]) / scale;
return {
x: xn,
y: yn
};
};
d3.demo.util.getCTMCoords = function(x, y, ctm) {
var xn = ctm.e + x * ctm.a;
var yn = ctm.f + y * ctm.d;
return {
x: xn,
y: yn
};
};
d3.demo.util.uuid = function() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
};
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
function log(message, args) {
console.log(message, args);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
body {
width: 100%;
height: 100%;
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.demo .canvas .background {
fill: #F3F3F3;
stroke: #333333;
}
.demo .wrapper.outer > .background {
fill: #000000;
}
.demo .wrapper.inner > .background {
fill: #DDDDDD;
}
rect.selection {
stroke : #111111;
stroke-dasharray: 2px;
stroke-opacity : 0.75;
fill : transparent;
}
/* SHAPES */
.demo .shape .background {
fill: #0078E7;
stroke: #333333;
stroke-width: 0.5;
}
.demo .shape.selected > .background {
stroke-dasharray: 2px;
stroke-width : 3;
stroke: #000000;
filter: "";
}
.demo .shape .label {
font : 12px sans-serif;
pointer-events : none;
fill: #FFFFFF;
}
.demo .container .containerGroup .background,
.demo .flowbox > .background {
fill: #FFFFFF;
stroke: #999999;
}
.demo .flowbox .node > .background {
fill: #2ECC71;
stroke: #333333;
stroke-width: 0.5;
}
.demo .flowbox .node > .label {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
fill: #000000;
stroke-width: 0;
}
.demo .clippath .background {
fill: #FFFFFF;
}
/* HANDLES */
.demo .handle .background {
fill: #F1C40F;
stroke: #333333;
stroke-width: 1;
}
.demo .handle .vertical {
cursor: ns-resize;
}
.demo .handle .horizontal {
cursor: ew-resize;
}
/* SVG */
svg *::selection {
background: transparent;
}
svg *::-moz-selection {
background: transparent;
}
svg *::-webkit-selection {
background: transparent;
}
/* HTML */
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12px;
}
.pure-button {
font-family: inherit;
font-size: 100%;
*font-size: 90%; /*IE 6/7 - To reduce IE's oversized button text*/
*overflow: visible; /*IE 6/7 - Because of IE's overly large left/right padding on buttons */
padding: 0.5em 1em;
color: #444; /* rgba not supported (IE 8) */
color: rgba(0, 0, 0, 0.80); /* rgba supported */
*color: #444; /* IE 6 & 7 */
border: 1px solid #999; /*IE 6/7/8*/
border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
background-color: #E6E6E6;
text-decoration: none;
border-radius: 2px;
margin: 0 5px;
}
.pure-button-hover,
.pure-button:hover,
.pure-button:focus {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000',GradientType=0);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10)));
background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.10));
background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
}
.pure-button:focus {
outline: 0;
}
.pure-button-active,
.pure-button:active {
box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
}
/* Firefox: Get rid of the inner focus border */
.pure-button::-moz-focus-inner{
padding: 0;
border: 0;
}
.pure-button-primary,
.pure-button-selected,
a.pure-button-primary,
a.pure-button-selected {
background-color: rgb(0, 120, 231);
color: #fff;
}
ul {
margin-top: 4px;
}
</style>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="demo.base.js"></script>
<script src="demo.util.js"></script>
<script src="demo.shape.js"></script>
<script src="demo.container.js"></script>
<script src="demo.handle.js"></script>
<script src="demo.layout.flow.js"></script>
<script src="demo.flowbox.js"></script>
</head>
<body>
<ul>
<li>Use resize handles to change width of shapes and reflow children</li>
<li>Drag containers around and drag on the background to use selection rectangle</li>
<li>Add additional container using the link provided</li>
</ul></h5>
<button id="addContainer" class="pure-button pure-button-primary">Add Container</button>
<p/>
<div id="demo"></div>
<script type="text/javascript">
var lastXY = 10;
var canvasWidth = 800;
var demo = d3.demo.app().width(600).height(600);
d3.select("#demo").call(demo);
d3.select("#addContainer").on("click", function() {
addContainer("Container").x(lastXY).y(lastXY).width(200).height(350);
lastXY += 10;
});
function addContainer(titleArg) {
var container = d3.demo.container();
demo.addShape(container
.label(titleArg)
.children([{id:1,name:"child1"}, {id:2,name:"child2"}, {id:3,name:"child3"},
{id:4,name:"child4"}, {id:5,name:"child5"}, {id:6,name:"child6"},
{id:7,name:"child7"}, {id:8,name:"child8"}, {id:9,name:"child9"},
{id:10,name:"child10"}, {id:11,name:"child11"}, {id:12,name:"child12"},
{id:13,name:"child13"}, {id:14,name:"child14"}, {id:15,name:"child15"}]));
return container;
}
addContainer("RESIZE ME").x(20).y(10).width(200).height(475);
addContainer("RESIZE ME").x(300).y(10).width(210).height(400);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment