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; };