I need a very basic example to create a stack chart like this example with a predefined array like this:
var data = [[ 1, 4, 2, 7],
[21, 2, 5, 10],
[ 1, 17, 16, 6]]
Whatever I do ends creating errors. E.g. TypeError: data is undefined.
Here is my simplified code so far:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v2.js?2.9.5"></script>
<script>
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var data = [[ 1, 4, 2, 7],
[21, 2, 5, 10],
[ 1, 17, 16, 6]];
var x = d3.scale.linear()
.range([0, width])
.domain([0,3]);
var y = d3.scale.linear()
.range([height, 0])
.domain([0,25]);
var z = d3.scale.category20c();
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var stack = d3.layout.stack(data)
.offset("zero")
.values(function(d) { return d; })
.x(function(d, i) { return i; })
.y(function(d) { return d; });
var area = d3.svg.area()
.x(function(d, i) { return x(i); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
svg.selectAll(".layer")
.data(stack)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return colors[i]; });
</script>
You can see a working example at http://jsfiddle.net/DyrsK/2/.
Generally I find it easier to permute the input data a little bit to get into the default form that d3 expects. For this example I took your data and computed the x, y and y0 values and then passed that to the default stack layout.
var data = [[ 1, 4, 2, 7],
[21, 2, 5, 10],
[ 1, 17, 16, 6]];
// permute the data
data = data.map(function(d) {
return d.map(function(p, i) {
return {x:i, y:p, y0:0};
});
});
I think there is an easier way to do this, but I had trouble with the out() function of d3.layout.stack() since your input data was a value but the out() function expects it to be a reference value. This meant that there wasn't a way to update the values with the computed offsets and so the data being returned by stack() was always equal to the input values.
After getting the stack function to work, the rest pretty much followed from the example you linked to:
var stack = d3.layout.stack()
.offset("zero")
var layers = stack(data);
var area = d3.svg.area()
.interpolate('cardinal')
.x(function(d, i) { return x(i); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d); })
.style("fill", function(d, i) { return colors(i); });
Hope this helps!
Related
I have a rectangle defined by 4 points. I want to move it to the left or right by specific distance. By moving I mean that result rectangle should be parallel to the original and if we put straights through corresponding points we will get rectangular cuboid.
On an image I am given coordinates of points A,B,C,D and distance H.
How can I calculate 4 new points using Three.js?
I guess it has something to do with projection, but I couldn't find an easy way to do it.
Just an example. Aqua lines are base, yellow lines are shifted ones:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 5, 5);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.enablePan = false;
scene.add(new THREE.GridHelper());
let dir = new THREE.Vector3(0, 0, 1);
let colors = [];
let ptsBase = [
[-1, 1], [1, 1], [1, -1], [-1, -1]
].map(p => {
colors.push(0, 1, 1);
return new THREE.Vector3(p[0], p[1], 0);
});
let ptsShift = ptsBase.map(p => {
colors.push(1, 1, 0);
return p.clone().addScaledVector(dir, 2)
});
let ptsFinal = ptsBase.concat(ptsShift);
let g = new THREE.BufferGeometry().setFromPoints(ptsFinal);
g.setIndex([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7]);
g.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
let m = new THREE.LineBasicMaterial({vertexColors: true});
let l = new THREE.LineSegments(g, m);
scene.add(l);
renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});
</script>
What I found to be working is getting normal vector, multiplying it by distance, and adding it to my point vectors.
I did it like this
let pointA = new THREE.Vector3(0, 0, 0);
let pointB = new THREE.Vector3(1, 0, 0);
let pointC = new THREE.Vector3(1, 1, 0);
let pointD = new THREE.Vector3(0, 1, 0);
const distance = 0.5;
let triangle = new THREE.Triangle(pointA, pointB, pointC);
let plane = new THREE.Plane();
triangle.getPlane(plane);
let normalVector = plane.normal.multiplyScalar(distance);
pointA1 = pointA.clone().add(normalVector);
pointB1 = pointB.clone().add(normalVector);
pointC1 = pointC.clone().add(normalVector);
pointD1 = pointD.clone().add(normalVector);
I am trying to load a CSV data set into d3 by assigning it to a variable, but it seems that I keep receiving an error saying that enter() is not a function. I think the issue lies in the way I'm loading the CSV data.
For reference, I'm following this tutorial: http://duspviz.mit.edu/d3-workshop/scatterplots-and-more/
Here is my code for reference.
var ratData = [];
d3.csv("rat-data.csv", function(d) {
return {
city : d.city, // city name
rats : +d.rats // force value of rats to be number (+)
};
}, function(error, rows) { // catch error if error, read rows
ratData = rows; // set ratData equal to rows
console.log(ratData);
createVisualization(); // call function to create chart
});
function createVisualization(){
// Width and height of SVG
var w = 150;
var h = 175;
// Get length of dataset
var arrayLength = ratData.length; // length of dataset
var maxValue = d3.max(ratData, function(d) { return +d.rats;} ); // get maximum
var x_axisLength = 100; // length of x-axis in our layout
var y_axisLength = 100; // length of y-axis in our layout
// Use a scale for the height of the visualization
var yScale = d3.scaleLinear()
.domain([0, maxValue])
.range([0, y_axisLength]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Select and generate rectangle elements
svg.selectAll( "rect" )
.data( ratData )
.enter()
.append("rect")
.attr( "x", function(d,i){
return i * (x_axisLength/arrayLength) + 30; // Set x coordinate of rectangle to index of data value (i) *25
})
.attr( "y", function(d){
return h - yScale(d.rats); // Set y coordinate of rect using the y scale
})
.attr( "width", (x_axisLength/arrayLength) - 1)
.attr( "height", function(d){
return yScale(d.rats); // Set height of using the scale
})
.attr( "fill", "steelblue");
// Create y-axis
svg.append("line")
.attr("x1", 30)
.attr("y1", 75)
.attr("x2", 30)
.attr("y2", 175)
.attr("stroke-width", 2)
.attr("stroke", "black");
// Create x-axis
svg.append("line")
.attr("x1", 30)
.attr("y1", 175)
.attr("x2", 130)
.attr("y2", 175)
.attr("stroke-width", 2)
.attr("stroke", "black");
// y-axis label
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.text("No. of Rats")
.attr("transform", "translate(20, 20) rotate(-90)")
.attr("font-size", "14")
.attr("font-family", "'Open Sans', sans-serif");
}; // end of function
I have generated a Sankey diagram as shown above using d3 code (.js file) mentioned below [the .html and .css files are not quoted here].
Now I want the Sankey diagram to look like below with node "Technology" and "Strategy" appearing apart as a fourth level:
What are the necessary changes to be done in the D3 code?
var svg = d3.select("svg").attr("style", "outline: thin solid grey;"),
width = +svg.attr("width"),
height = +svg.attr("height");
var formatNumber = d3.format(",.0f"),
format = function(d) { return formatNumber(d) + " TWh"; },
color = d3.scaleOrdinal(d3.schemeCategory10);
var school = {"nodes": [
{"name":"High School"}, // 0
{"name":"Community College"}, // 1
{"name":"Finance"}, // 2
{"name":"Accounting"}, // 3
{"name":"ITS"}, // 4
{"name":"Marketing"}, // 5
{"name":"Analytics"}, // 6
{"name":"Security"}, // 7
{"name":"Consulting"}, // 8
{"name":"Banking"}, // 9
{"name":"Internal"}, // 10
{"name":"Securities"}, // 11
{"name":"Public"}, // 12
{"name":"Audting"}, // 13
{"name":"Internal"}, // 14
{"name":"Retail"}, // 15
{"name":"Technology"}, // 16
{"name":"Strategy"} // 17
],
"links":[
// FirstYear
{"source":0,"target":2,"value":33},
{"source":0,"target":3,"value":42},
{"source":0,"target":4,"value":74},
{"source":0,"target":5,"value":60},
// Community College
{"source":1,"target":2,"value":7},
{"source":1,"target":3,"value":13},
{"source":1,"target":4,"value":11},
{"source":1,"target":5,"value":9},
// Finance
{"source":2,"target":9,"value":16},
{"source":2,"target":10,"value":14},
{"source":2,"target":11,"value":10},
// Accounting
{"source":3,"target":12,"value":20},
{"source":3,"target":13,"value":12},
{"source":3,"target":7,"value":8},
{"source":3,"target":14,"value":15},
// Marketing
{"source":5,"target":6,"value":30},
{"source":5,"target":15,"value":39},
// ITS
{"source":4,"target":6,"value":40},
{"source":4,"target":7,"value":20},
{"source":4,"target":12,"value":6},
{"source":4,"target":8,"value":19},
// ITS Consulting
{"source":8,"target":16,"value":10},
{"source":8,"target":17,"value":9},
]};
var sankey = d3.sankey()
.nodeWidth(15)
.nodePadding(10)
.extent([[1, 1], [width - 1, height - 6]]);
var link = svg.append("g")
.attr("class", "links")
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("path");
var node = svg.append("g")
.attr("class", "nodes")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("g");
sankey(school);
link = link
.data(school.links)
.enter().append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke-width", function(d) { return Math.max(1, d.width); });
// link hover values
link.append("title")
.text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
node = node
.data(school.nodes)
.enter().append("g");
node.append("rect")
.attr("x", function(d) { return d.x0; })
.attr("y", function(d) { return d.y0; })
.attr("height", function(d) { return d.y1 - d.y0; })
.attr("width", function(d) { return d.x1 - d.x0; })
.attr("fill", function(d) { return color(d.name.replace(/ .*/, "")); })
.attr("stroke", "#000");
node.append("text")
.attr("x", function(d) { return d.x0 - 6; })
.attr("y", function(d) { return (d.y1 + d.y0) / 2; })
.attr("dy", "0.35em")
.attr("text-anchor", "end")
.text(function(d) { return d.name; })
.filter(function(d) { return d.x0 < width / 2; })
.attr("x", function(d) { return d.x1 + 6; })
.attr("text-anchor", "start");
svg.append("text")
.attr("x", 10)
.attr("y", 30)
.attr("class", "graphTitle")
.text("STUDENT CHOICES");
svg.append("text")
.attr("x", width - 80)
.attr("y", height - 10)
.attr("class", "footnote")
.text("data is fictitious");
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/d3-sankey#0"></script>
<svg width="600" height="500"></svg>
The alignment of d3.sankey can be configured using .nodeAlign(), and for your requirement, you will need .nodeAlign(d3.sankeyLeft)
If it is not specified, the alignment defaults to d3.sankeyJustify, which is what you are currently seeing.
https://github.com/d3/d3-sankey#alignments
For those who are looking for a quick ans. Have a nice day!
var sankey = d3.sankey()
.nodeWidth(15)
.nodePadding(10)
.nodeAlign(function (node) {
// you may specify the horizatonal location here
// i.e. if your data structure contain node.horizontalPosition (an integer)
// you can return node.horizontalPosition
return node.depth; //align left
})
.extent([[1, 1], [width - 1, height - 6]]);
I have created a stripped down JSFiddle of my D3 chart. I have made it responsive (with viewbox and preserveaspectratio) using the solution at:
responsive D3 chart
When I resize the window and make it smaller, some of the grid lines seem to be disappearing and reappearing. I presume this will look bad at small resolutions (eg. 320x480 mobile phone). Is there a way to preserve my gridlines when the window gets resized smaller?
HTML code:
<!--//d3 chart//-->
<div class="centre-div"></div>
CSS Code:
.centre-div {
margin: 0 auto;
max-width: 550px;
}
/* D3 chart css */
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
JS code:
//function createScatterplot() {
//Width and height
var margin = {
top: 15,
right: 2,
bottom: 2,
left: 2
};
//define width and height as the inner dimensions of the chart area.
var width = 550 - margin.left - margin.right;
var height = 550 - margin.top - margin.bottom;
var padding = 10;
//define svg as a G element that translates the origin to the top-left corner of the chart area.
//add <svg> to the last <div class="centre-div"> tag on the html page
//this allows me to reuse the createScatterplot() function to draw multiple charts
var svg = d3.select(d3.selectAll(".centre-div")[0].pop()).append("svg")
//.attr("width", width + margin.left + margin.right)
//.attr("height", height + margin.top + margin.bottom)
//make svg responsive
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 550 550")
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//With this convention, all subsequent code can ignore margins.
//http://bl.ocks.org/mbostock/3019563
//Static dataset
var dataset = [
[5, -2, "A"],
[-4, -9, "B"],
[2, 5, "C"],
[1, -3, "D"],
[-3, 5, "E"],
[4, 1, "F"],
[4, 4, "G"],
[5, 7, "H"],
[-5, -2, "I"],
[0, 8, "J"],
[-6, -5, "K"]
];
//Create scale functions
var xScale = d3.scale.linear()
.domain([-10, 11])
.range([padding, width - padding * 2]);
var yScale = d3.scale.linear()
.domain([-10, 11])
.range([height - padding, padding]);
//different scale for gridlines, so last tick has no line
var xScale2 = d3.scale.linear()
.domain([-10, 10])
.range([padding, width - padding * 2]);
var yScale2 = d3.scale.linear()
.domain([-10, 10])
.range([height - padding, padding]);
//add arrowheads
defs = svg.append("defs")
defs.append("marker")
.attr({
"id": "arrow",
"viewBox": "-5 -5 10 10",
"refX": 0,
"refY": 0,
"markerWidth": 7, //marker size
"markerHeight": 7, //marker size
"orient": "auto"
})
.append("path")
.attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
.attr("fill", "#000");
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(22)
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(22)
//create scatterplot crosses
svg.selectAll("line.diag1")
.data(dataset)
.enter()
.append("line")
.attr({
"class": "diag1",
"x1": function(d) {
return xScale(d[0]) - 4;
},
"y1": function(d) {
return yScale(d[1]) - 4;
},
"x2": function(d) {
return xScale(d[0]) + 4;
},
"y2": function(d) {
return yScale(d[1]) + 4;
},
"stroke": "#006CCA",
"opacity": "1",
"stroke-width": "2px"
});
svg.selectAll("line.diag2")
.data(dataset)
.enter()
.append("line")
.attr({
"class": "diag2",
"x1": function(d) {
return xScale(d[0]) + 4;
},
"y1": function(d) {
return yScale(d[1]) - 4;
},
"x2": function(d) {
return xScale(d[0]) - 4;
},
"y2": function(d) {
return yScale(d[1]) + 4;
},
"stroke": "#006CCA",
"opacity": "1",
"stroke-width": "2px"
});
//Create X axis
svg.append("g")
.attr("class", "axis")
.style("stroke-width", 2)
.attr("transform", "translate(0," + 11 * (height) / 21 + ")")
.call(xAxis)
//add x label
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", 15)
.attr("font-style", "italic")
.attr("font-weight", "bold")
.style("text-anchor", "end")
.text("x");
//Create Y axis
svg.append("g")
.attr("class", "axis")
.style("stroke-width", 2)
.attr("transform", "translate(" + 10 * (width - padding) / 21 + ",0)")
.call(yAxis)
//add y label
.append("text")
.attr("class", "label")
.attr("x", -10)
.attr("y", -5)
.attr("font-style", "italic")
.attr("font-weight", "bold")
.style("text-anchor", "end")
.text("y");
//add arrowheads to axis ends
//add line on top of x-axis and arrowhead
svg.append("line")
.attr({
"x1": 0,
"y1": 11 * height / 21,
"x2": width - padding * 1.5,
"y2": 11 * height / 21,
"stroke": "black",
"stroke-width": "2px",
"marker-end": "url(#arrow)"
});
//add line on top of y-axis and arrowhead
svg.append("line")
.attr({
"x1": 10 * (width - padding) / 21,
"y1": height,
"x2": 10 * (width - padding) / 21,
"y2": 0.4 * padding,
"stroke": "black",
"stroke-width": "2px",
"marker-end": "url(#arrow)"
});
//Assuming that you have Mike Bostock's standard margins defined and you have defined a linear scale for the y-axis the following code will create horizontal gridlines without using tickSize().
//https://stackoverflow.com/questions/15580300/proper-way-to-draw-gridlines
//create horizontal grid lines
var gridwidth = 19 * width / 20;
var gridheight = 19 * height / 20;
svg.selectAll("line.horizontalGrid").data(yScale2.ticks(20)).enter()
.append("line")
.attr({
"class": "horizontalGrid",
"x1": 0,
"x2": gridwidth,
"y1": function(d) {
return yScale(d);
},
"y2": function(d) {
return yScale(d);
},
"fill": "none",
"shape-rendering": "crispEdges",
"stroke": "black",
"stroke-width": "1px",
"opacity": "0.3"
});
//create vertical gridlines
svg.selectAll("line.verticalGrid").data(xScale2.ticks(20)).enter()
.append("line")
.attr({
"class": "verticalGrid",
"y1": height - gridheight,
"y2": height,
"x1": function(d) {
return xScale(d);
},
"x2": function(d) {
return xScale(d);
},
"fill": "none",
"shape-rendering": "crispEdges",
"stroke": "black",
"stroke-width": "1px",
"opacity": "0.3"
});
//remove last ticks and zero ticks
svg.selectAll(".tick")
.filter(function(d) {
return d === 11;
})
.remove();
svg.selectAll(".tick")
.filter(function(d) {
return d === 0;
})
.remove();
//add a custom origin identifier
svg.append("text")
.attr({
"class": "origintext",
"x": 455 * width / 1000,
"y": 552 * height / 1000,
"text-anchor": "end",
"font-size": "65%"
})
.text("0");
//add labels to points plotted
svg.selectAll("textlabels")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[2];
})
.attr("x", function(d) {
return xScale(d[0]) + 5;
})
.attr("y", function(d) {
return yScale(d[1]) - 5;
})
.attr("font-weight", "bold")
.attr("font-size", "12px")
.attr("fill", "black");
//}
That is an aliasing effect which will occur because the way the lines will get rendered is influenced by various factors. The main three of them being stroke width, position and rendering mode. For using shape-rendering: crispEdges the SVG spec states:
To achieve crisp edges, the user agent might turn off anti-aliasing for all lines...
Depending on the scaling and the translation of the line it may be calculated to appear between two screen pixels while the scaled stroke width is not broad enough to color any of those adjacent screen pixels. That way the lines seem to randomly disappear and appear again.
Further explanations can be found in "Why is SVG stroke-width : 1 making lines transparent?" or in my answer to "Drew a straight line, but it is crooked d3".
For your code you can change the rendering behaviour by using shape-rendering: geometricPrecision instead of crispEdges when drawing the grid lines. Have a look at the updated JSFiddle for a working example.
In my case I simply solved this issue by setting "showMaxMin" to false.
lineChart.xAxis.showMaxMin(false).tickValues(xAxisTickValues).tickFormat(function (d) {
if (typeof d === 'string') {
d = parseFloat(d);
}
return d3.time.format("%d %b")(new Date(d));
});
I am trying to create panel components that will hold some visualizations.
I am making the panel component with svgs. They look ok, but I am getting some weird behavior when resizing and moving the panels.
var groups = ["uno", "dos", "tres", "cuatro"];
var w = 350;
var x = 0;
var y = 0;
var width = 800;
var h = 200;
var height = 800;
var val = [];
var drag = d3.behavior.drag()
.origin(Object)
.on("drag", move);
var resize = d3.behavior.drag()
.origin(Object)
.on("drag", dragResize);
svg = d3.select("body").append("div").append("svg");
charts = svg.selectAll("g.chart")
.data(groups); //(dims);
box = charts.enter()
.append("g").classed("chart", true)
.attr("id", function(d,i) { return "box"+i})
//.data([{x: 95, y: 0}]);
box.append("rect").classed("box", true)
var t = box.append("rect").classed("titleBox", true)
t.call(drag);
box.append("text").classed("title", true).data(groups)
box.append("text").classed("legend", true).data(groups)
box.append("rect").classed("icon", true)
.call(resize);
box.selectAll("rect.box")
.data([{x: 95, y: 0}])
.attr({
x: function(d) { return d.x; },
y: function(d) { return d.y; },
width: w,
height: function(d) { return 200}//d.length*30 + 60}
})
box.selectAll("rect.titleBox")
.classed("drag", true)
.data([{x: 95, y: 0}])
.attr({
x: function(d) { return d.x; },
y: function(d) { return d.y; },
width: w,
height: 25,
fill: "#000000"
})
box.selectAll("text.title")
.attr({
x: 105,
y: 20,
width: 350,
height: 25,
fill: "#ffffff"
})
.text(function(d) {
console.log("i from title "+ d);
return d;
})
box.selectAll("text.legend")
.attr({
x: 105,
y: 45,
width: 200,
height: 25,
fill: "#999999"
})
.text(function(d) {
return d;
})
box.selectAll("rect.icon")
.data([{x: 429, y: 184}])
.attr({
x: function(d) { return d.x; },
y: function(d) { return d.y; },
width: 16,
height: 16,
fill: "#999999"
})
var dx = 429;
var dy = 184;
function move(){
var dragTarget = d3.select(this);
var dragObject = d3.select(this.parentNode);
console.log("move x:"+x+" y:"+y);
//console.log("d3.event.x:"+d3.event.x+" d3.event.y:"+d3.event.y);
x += d3.event.x - parseInt(dragTarget.attr('x'));
y += d3.event.y - parseInt(dragTarget.attr("y"));
console.log("x:"+x+" y:"+y);
dragObject
.attr("transform", "translate(" + x + "," + y + ")")
};
function dragResize(){
var dragx = Math.max(dx + (16/2), Math.min(w, dx + width + d3.event.dx));
var dragy = Math.max(dy + (16/2), Math.min(h, dy + height + d3.event.dy));
//console.log("resize x:"+x+" y:"+y);
console.log("d3.event.x:"+d3.event.dx+" d3.event.y:"+d3.event.dy);
var dragTarget = d3.select(this);
var dragObject = d3.select(this.parentNode);
var o = dragObject.select("rect.box");
var o1 = dragObject.select("rect.titleBox");
var oldx = dx;
var oldy = dy;
dx = Math.max(0, Math.min(dx + width - (16 / 2), d3.event.x));
dy = Math.max(0, Math.min(dy + height - (16 ), d3.event.y));
w = w - (oldx - dx);
h = h - (oldy - dy);
dragTarget
.attr("x", function(d) { return dragx - (16/2) })
.attr("y", function(d) { return dragy - (16) })
o.attr("width", w)
.attr("height", h);
o1.attr("width", w);
};
I have posted the code at http://jsfiddle.net/dtqY5/
The problem is the following: I can move each panel, by dragging the title area, with no problem. Howvwer, after I resize any of the panels, I cannot move them anymore. They jump to their original position. The x and y becones NaN, but I cannot understand why.
ANy ideas and suggestions will be welcomed.
D3 uses the drag.origin accessor you provide to calculate an offset. Since the access you provide is just an empty object, this offset is NaN which results in x and y on the event also being NaN.
If you remove drag.origin altogether it uses the current mouse position as the origin which makes the panels jump when you start dragging. If you specify the origin to be the position of the shape being dragged it looks better:
.origin(function() {
var current = d3.select(this);
return {x: current.attr("x"), y: current.attr("y") };
})
Here's an updated fiddle: http://jsfiddle.net/4nvhc/