Adding nodes inside svg rect using d3 force layout - javascript

I have drawn four svg rect diagram...with different colors....
I'm trying to add node inside of those svg rect...but I'm getting only the svg rect without node inside them...I know that I have done something wrong with data...
But I'm not able to figure them out..I'm just one month old to D3..please advice me on this....
If you run the code below you can see my mistake....
<!DOCTYPE html>
<html>
<head>
<script src="../D3/d3.min.js"></script>
</head>
<body>
<style>
</style>
<script type="text/javascript">
var width = 500,
height = 500;
var nodes = [
{ x: width / 3, y: height / 2 }
//{ x: 2 * width / 3, y: height / 1 },
//{ x: 3 * width / 3, y: height / 2 },
//{ x: 4 * width / 3, y: height / 2 }
];
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
var svgcontainer = d3.select("body")
.append("svg")
.attr("width", 1000)
.attr("height", 900);
var rectdata = [{ "x": 50, "y": 70, "width": 600, "height": 150,"rx":80,"ry":80,"fill":"skyblue"},
{ "x": 50, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "palegreen" },
{ "x": 440, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "orange" },
{ "x": 50, "y": 700, "width": 600, "height": 150, "rx": 80, "ry": 80, "fill": "brown" }];
var svgrect = svgcontainer.selectAll("rect").data(rectdata).enter().append("rect");
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('rect')
.attr('class', 'node');
force.on('end', function () {
svgrect.attr("x", function (d, i) { return d.x; })
.attr("y", function (d, i) { return d.y; })
.attr("rx", function (d, i) { return d.rx; })
.attr("ry", function (d, i) { return d.ry; })
.attr("width", function (d, i) { return d.width; })
.attr("height", function (d, i) { return d.height; })
.attr("fill", function (d, i) { return d.fill; });
});
force.start();
</script>
</body>
</html>

You aren't giving the node any attributes. I take it you want a circle and not a rect :
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('circle')
.attr('class', 'node')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('r', 10)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
Notice the translate at the bottom. If you are using the force layout in D3, the tick function should take care of this, but it looks like you don't have one, so you have to insert it after you create the nodes.
If you didn't want circles and wanted rectangles then this should do :
var nodeRect = svgcontainer.selectAll('.nodeRect')
.data(nodes)
.enter().append('rect')
.attr('class', 'nodeRect')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('width', 100)
.attr('height', 50)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
Working fiddle with both : https://jsfiddle.net/reko91/n13kqvw9/
var width = 500,
height = 500;
var nodes = [
{ x: width / 3, y: height / 2 }
//{ x: 2 * width / 3, y: height / 1 },
//{ x: 3 * width / 3, y: height / 2 },
//{ x: 4 * width / 3, y: height / 2 }
];
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
var svgcontainer = d3.select("body")
.append("svg")
.attr("width", 1000)
.attr("height", 900);
var rectdata = [{ "x": 50, "y": 70, "width": 600, "height": 150,"rx":80,"ry":80,"fill":"skyblue"},
{ "x": 50, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "palegreen" },
{ "x": 440, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "orange" },
{ "x": 50, "y": 700, "width": 600, "height": 150, "rx": 80, "ry": 80, "fill": "brown" }];
var svgrect = svgcontainer.selectAll("rect").data(rectdata).enter().append("rect");
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('circle')
.attr('class', 'node')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('r', 10)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
var nodeRect = svgcontainer.selectAll('.nodeRect')
.data(nodes)
.enter().append('rect')
.attr('class', 'nodeRect')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('width', 100)
.attr('height', 50)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
force.on('end', function () {
svgrect.attr("x", function (d, i) { return d.x; })
.attr("y", function (d, i) { return d.y; })
.attr("rx", function (d, i) { return d.rx; })
.attr("ry", function (d, i) { return d.ry; })
.attr("width", function (d, i) { return d.width; })
.attr("height", function (d, i) { return d.height; })
.attr("fill", function (d, i) { return d.fill; });
});
force.start();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Related

How to use images and circles with force using D3.js?

I am completely lost trying to spawn circles with pictures inside that all move within a force.drag. They should be created based on a list of arrays. Any help is really appreciated!
This is my code so far:
var data2 = [
{id: 1, name: "Sachin", pop: 200, x: 0, y: 0, color: 'red', image: "https://picsum.photos/900" },
{id: 2, name: "Murali", pop: 100, x: 200, y: 200, color: 'green', image: "https://random.imagecdn.app/500/500" }
]
var body = d3.select("body")
var svg = body.append("svg")
.attr("width", 800)
.attr("height", 800)
data2.forEach(function(d){
svg.append("clipPath")
.attr('id', d.id)
.append('circle')
.attr("cx", d.x + d.pop /2)
.attr("cy", d.y + d.pop / 2)
.attr("r", d.pop /2)
.attr("", console.log(d))
.style("fill", "green")
.attr("", console.log("done! with this one"))
})
data2.forEach(function(d){
svg.append('image')
.attr('xlink:href',d.image)
.attr('width', d3.sum([d.pop]))
.attr('height', d3.sum([d.pop]))
.attr('x', d.x)
.attr('y', d.y)
.attr('clip-path','url(#' + d.id + ')');
});
But this only gives me this:
But I am trying to make this...
and applying force to it as shown in this snippet:
var data2 = [
{id: 1, name: "Sachin", pop: 20, color: 'red', image: "https://picsum.photos/900" },
{id: 2, name: "Murali", pop: 10, color: 'green', image: "https://random.imagecdn.app/500/500" }
]
var width = 400//Dimensions.get('window').width,
var height = 400//Dimensions.get('window').height,
// create SVG
var body = d3.select("body") //SVG ÄR HELA ARBETSYTAN
var svg = body.append("svg")
.attr("width", width)
.attr("height", height)
//.style("background", "#000000")
// init a force layout, using the nodes and edges in dataset
var force = d3.layout.force()
.nodes(data2)
//.links(data.edges)
.size([width, height])
.charge([-300]) //.linkDistance([100])
.start()
// define 10 random colors
//var colors = d3.scale.category10()*/
var drums = svg.selectAll("circle")
.data(data2)
.enter()
.append("circle")
drums.attr("cx", function(d) { return width/2 }) //för att vara olika för varje item.
.attr("cy", height/2)
.attr("r", function(d) { return d.pop })
.attr("", function(d) { console.log(d) })
.call(force.drag)
drums.style("fill", function(d) {
if (!d.image) {
return ("url(#" + d.id + ")"); //console.log(d.image)
}else{
return d.color
}
})
force.on("tick", function() {
(svg.selectAll('circle') //drums
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) { return d.y })
)
})
drums.on("click", function(d) {
console.log(d)
d3.select(this)
.attr("r" , d3.sum([d3.select(this).attr("r"),10]))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.4/d3.min.js"></script>
Thank you so much for taking a look into this! :)

d3 drag multiple text elements inside a group SVG

I am new to using d3.js. I am trying to append multiple text elements in a svg group. With that, I want to be able to drag the group of multiple text.
So for an example:
export function testNode (config = {}) {
let { svg, rectX, rectY, text1, text2 } = config
var data = [{ x: rectX, y:rectY, label: text1, label2: text2, labelX: rectX + 100, labelY: rectY + 200, labelX2: rectX + 300, labelY2: rectY + 300 }]
var group = svg.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform",
"translate(" + 0 + "," + 0 + ")")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
group.append("text")
.data(data)
.attr("x", (d) => { return d.labelX })
.attr("y", (d) => { return d.labelY })
.attr("font-size", "1em")
.attr("color", "black")
.text((d) => { return d.label });
group.append("text")
.data(data)
.attr("x", (d) => { return d.labelX2 })
.attr("y", (d) => { return d.labelY2 })
.attr("font-size", ".75em")
.attr("color", "black")
.attr("class", "label")
.text((d) => { return d.metricValue_01 });
function dragStarted() {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("text")
.attr("x", d.labelX = d3.event.x + 10)
.attr("y", d.labelY = d3.event.y + 20);
d3.select(this).select("text")
.attr("x", d.labelX2 = d3.event.x + 10)
.attr("y", d.labelY2 = d3.event.y + 20);
function dragended() {
d3.select(this).classed("active", false);
}
If I use the selectAll method, the text gets clumped together. Therefore, I was wondering if I can drag the text group in their proper position based on the coordinate I give it (while being dragged). Anyways please let me know if I need to provide any further information. Thank you
If you want to select the second label, but don't want to use selectAll as it selects both, you can give the labels classes when appending and select those when dragging:
d3.select(this).select(".bigLabel")
.attr("x", d.labelX = d3.event.x + 10)
.attr("y", d.labelY = d3.event.y + 20);
d3.select(this).select(".smallLabel")
.attr("x", d.labelX2 = d3.event.x + 10)
.attr("y", d.labelY2 = d3.event.y + 20);
Though of course this will set the same coordinate for both labels unless you specify an offset, as below:
var data = [
{ x: 100, x2: 100, y: 100, y2: 120, label: "label1", value: "17%" },
{ x: 300, x2: 300, y: 200, y2: 220, label: "label2", value: "83%" },
{ x: 100, x2: 100, y: 200, y2: 220, label: "label3", value: "11%" },
{ x: 300, x2: 300, y: 100, y2: 120, label: "label4", value: "96%" }
];
var svg = d3.select("svg");
var labels = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.call(d3.drag()
.on("drag",drag));
labels.append("text")
.attr("font-size", "1em")
.attr("x", function(d) { return d.x;})
.attr("y", function(d) { return d.y;})
.text(function(d) { return d.label; })
.attr("class","label1");
labels.append("text")
.attr("font-size", ".75em")
.attr("x", function(d) { return d.x2;})
.attr("y", function(d) { return d.y2;})
.text(function(d) { return d.value; })
.attr("class","label2");
function drag(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this)
.select(".label1")
.attr("x", function(d) { return d.x = x; })
.attr("y", function(d) { return d.y = y; })
d3.select(this)
.select(".label2")
.attr("x", function(d) { return d.x2 = x; })
.attr("y", function(d) { return d.y2 = y + 20; })
}
text {
text-anchor:middle;
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="400"></svg>
I won't dive into the alternative in too much depth, but it applies the drag to the g, positioning both text labels at the same time. This can handle irregular spacing between sibling labels easier than the above:
var data = [
{ x: 100, y: 100, label: "label1", value: "17%" },
{ x: 300, y: 200, label: "label2", value: "83%" },
{ x: 100, y: 200, label: "label3", value: "11%" },
{ x: 300, y: 100, label: "label4", value: "96%" }
];
var svg = d3.select("svg");
var labels = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform",function(d) {
return "translate("+[d.x,d.y]+")";
})
.call(d3.drag().on("drag", drag));
labels.append("text")
.attr("font-size", "1em")
.text(function(d) { return d.label; });
labels.append("text")
.attr("font-size", ".75em")
.text(function(d) { return d.value; })
.attr("dy", "1em")
function drag(d) {
d3.select(this)
.attr("transform","translate("+[d.x=d3.event.x,d.y=d3.event.y]+")");
}
text {
text-anchor: middle;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="400"></svg>
Also, there is no need to use append("text").data(data), this is not doing anything - your datum is already bound to the newly appended element
Lastly, you can make this work with selectAll() if you set attributes using the second parameter of any provided function when setting attributes: (d,i)=>... i is the index of the element, so if your sibling labels are regularly spaced, you can use something like:
var data = [
{ x: 100, y: 100, label: "label1", value: "17%" },
{ x: 300, y: 200, label: "label2", value: "83%" },
{ x: 100, y: 200, label: "label3", value: "11%" },
{ x: 300, y: 100, label: "label4", value: "96%" }
];
var svg = d3.select("svg");
var labels = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.call(d3.drag()
.on("drag",drag));
labels.append("text")
.attr("font-size", "1em")
.attr("x", function(d) { return d.x;})
.attr("y", function(d) { return d.y;})
.text(function(d) { return d.label; })
labels.append("text")
.attr("font-size", ".75em")
.attr("x", function(d) { return d.x;})
.attr("y", function(d) { return d.y + 20;})
.text(function(d) { return d.value; })
function drag(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this)
.selectAll("text")
.attr("x", function(d) { return d.x = x; })
.attr("y", function(d,i) { d.y = y;
return d.y + i * 20;
})
}
text {
text-anchor:middle;
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="400"></svg>

D3 js bar chart pan

I try to create bar chart with zoom/pan functionality using d3 js. Zooming works perfectly but when I pan the chart to the left or to the right the bars go out of beside min and max X values. What I'm doing wrong?
please check this image with issue described
Here is the fiddle: https://jsfiddle.net/Cayman/vpn8mz4g/1/
function render_chart(){
var stack = d3.layout.stack();
var dataset = {
"categories": ['2018-06-01T00:00:00.000+03:00',
'2018-06-02T00:00:00.000+03:00',
'2018-06-03T00:00:00.000+03:00',
'2018-06-04T00:00:00.000+03:00',
'2018-06-05T00:00:00.000+03:00',
'2018-06-06T00:00:00.000+03:00',
'2018-06-07T00:00:00.000+03:00',
'2018-06-08T00:00:00.000+03:00',
'2018-06-09T00:00:00.000+03:00',
'2018-06-10T00:00:00.000+03:00',
'2018-06-11T00:00:00.000+03:00',
'2018-06-12T00:00:00.000+03:00'],
"series": ["New York","Mumbai","Bengaluru"],
"colors": ["#3498db","#e74c3c","#2ecc71"],
"layers": [
[
{"y":1,"y0":20,"month":"2018-06-01T00:00:00.000+03:00"},
{"y":2,"y0":18,"month":"2018-06-02T00:00:00.000+03:00"},
{"y":5,"y0":18,"month":"2018-06-03T00:00:00.000+03:00"},
{"y":10,"y0":20,"month":"2018-06-04T00:00:00.000+03:00"},
{"y":14,"y0":23,"month":"2018-06-05T00:00:00.000+03:00"},
{"y":18,"y0":29,"month":"2018-06-06T00:00:00.000+03:00"},
{"y":20,"y0":31,"month":"2018-06-07T00:00:00.000+03:00"},
{"y":20,"y0":29,"month":"2018-06-08T00:00:00.000+03:00"},
{"y":16,"y0":24,"month":"2018-06-09T00:00:00.000+03:00"},
{"y":10,"y0":19,"month":"2018-06-10T00:00:00.000+03:00"},
{"y":5,"y0":23,"month":"2018-06-11T00:00:00.000+03:00"},
{"y":3,"y0":20,"month":"2018-06-12T00:00:00.000+03:00"}
],
[
{"y":12,"y0":24,"month":"2018-06-01T00:00:00.000+03:00"},
{"y":14,"y0":25,"month":"2018-06-02T00:00:00.000+03:00"},
{"y":13,"y0":31,"month":"2018-06-03T00:00:00.000+03:00"},
{"y":16,"y0":32,"month":"2018-06-04T00:00:00.000+03:00"},
{"y":18,"y0":33,"month":"2018-06-05T00:00:00.000+03:00"},
{"y":19,"y0":29,"month":"2018-06-06T00:00:00.000+03:00"},
{"y":20,"y0":27,"month":"2018-06-07T00:00:00.000+03:00"},
{"y":18,"y0":26,"month":"2018-06-08T00:00:00.000+03:00"},
{"y":20,"y0":31,"month":"2018-06-09T00:00:00.000+03:00"},
{"y":17,"y0":29,"month":"2018-06-10T00:00:00.000+03:00"},
{"y":18,"y0":26,"month":"2018-06-11T00:00:00.000+03:00"},
{"y":14,"y0":24,"month":"2018-06-12T00:00:00.000+03:00"}
],[
{"y":8,"y0":24,"month":"2018-06-01T00:00:00.000+03:00"},
{"y":14,"y0":26,"month":"2018-06-02T00:00:00.000+03:00"},
{"y":12,"y0":31,"month":"2018-06-03T00:00:00.000+03:00"},
{"y":15,"y0":33,"month":"2018-06-04T00:00:00.000+03:00"},
{"y":18,"y0":37,"month":"2018-06-05T00:00:00.000+03:00"},
{"y":16,"y0":29,"month":"2018-06-06T00:00:00.000+03:00"},
{"y":17,"y0":27,"month":"2018-06-07T00:00:00.000+03:00"},
{"y":19,"y0":25,"month":"2018-06-08T00:00:00.000+03:00"},
{"y":25,"y0":30,"month":"2018-06-09T00:00:00.000+03:00"},
{"y":23,"y0":31,"month":"2018-06-10T00:00:00.000+03:00"},
{"y":11,"y0":26,"month":"2018-06-11T00:00:00.000+03:00"},
{"y":12,"y0":23,"month":"2018-06-12T00:00:00.000+03:00"}
]
]
}
dataset["categories"].forEach(function(d2) {
d = new Date(d2);
});
dataset["layers"].forEach(function(d) {
d.forEach(function(d2) {
d2.month = new Date(d2.month);
});
});
n = dataset["series"].length, // Number of Layers
m = dataset["layers"].length, // Number of Samples in 1 layer
yGroupMax = d3.max(dataset["layers"], function(layer) { return d3.max(layer, function(d) { return d.y0; }); });
yGroupMin = d3.min(dataset["layers"], function(layer) { return d3.min(layer, function(d) { return d.y; }); });
var pWidth = document.getElementById('chart1').offsetWidth;
var margin = {top: 50, right: 0, bottom: 50, left: 100},
width = pWidth - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain([new Date(dataset["categories"][0]),new Date(dataset["categories"][11]),])
.range([0, width]);
var y = d3.scale.linear()
.domain([yGroupMin, yGroupMax])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(dataset["categories"].length)
.tickPadding(6)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([0, Infinity])
.on("zoom", zoomed);
var svg = d3.select("#chart1").append("svg")
.call(zoom)
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d,i){d.map(function(b){b.colorIndex=i;return b;});return d;})
.enter().append("rect")
.transition()
.duration(500)
.delay(function(d, i) { return i * 10; })
.attr("x", function(d, i, j) {
var qqq = x(d.month);
var qqq2 = x(d.month) + 30 / n * j;
return x(d.month) + 30 / n * j;
})
.attr("width", 30 / n)
.transition()
.attr("y", function(d) { return y(d.y0); })
.attr("height", function(d) { return height - y(d.y0-0)})
.attr("class","bar")
.style("fill",function(d){return dataset["colors"][d.colorIndex];})
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("text")
.attr("x", width/3)
.attr("y", 0)
.attr("dx", ".71em")
.attr("dy", "-.71em")
.text("Min - Max Temperature (Month wise)");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
function zoomed() {
console.warn("zoom");
svg.select(".x.axis").call(xAxis);
console.log(d3.event.translate[0] + " " + d3.event.translate[1]);
svg.selectAll(".chart rect").attr("transform", "translate(" + d3.event.translate[0] + ",0)scale(" + d3.event.scale + ", 1)");
}
enter code here
}
You need to add a clip-path into the mix:
var svg = d3.select("#chart1").append("svg")
.call(zoom)
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// create clip-path that's the same size as drawing area
svg.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
svg = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer")
.attr('clip-path', 'url(#clip)'); //<-- clip drawing area
Running code:
$(document).ready(function() {
render_chart();
});
function render_chart() {
var stack = d3.layout.stack();
var dataset = {
"categories": ['2018-06-01T00:00:00.000+03:00',
'2018-06-02T00:00:00.000+03:00',
'2018-06-03T00:00:00.000+03:00',
'2018-06-04T00:00:00.000+03:00',
'2018-06-05T00:00:00.000+03:00',
'2018-06-06T00:00:00.000+03:00',
'2018-06-07T00:00:00.000+03:00',
'2018-06-08T00:00:00.000+03:00',
'2018-06-09T00:00:00.000+03:00',
'2018-06-10T00:00:00.000+03:00',
'2018-06-11T00:00:00.000+03:00',
'2018-06-12T00:00:00.000+03:00'
],
"series": ["New York", "Mumbai", "Bengaluru"],
"colors": ["#3498db", "#e74c3c", "#2ecc71"],
"layers": [
[{
"y": 1,
"y0": 20,
"month": "2018-06-01T00:00:00.000+03:00"
},
{
"y": 2,
"y0": 18,
"month": "2018-06-02T00:00:00.000+03:00"
},
{
"y": 5,
"y0": 18,
"month": "2018-06-03T00:00:00.000+03:00"
},
{
"y": 10,
"y0": 20,
"month": "2018-06-04T00:00:00.000+03:00"
},
{
"y": 14,
"y0": 23,
"month": "2018-06-05T00:00:00.000+03:00"
},
{
"y": 18,
"y0": 29,
"month": "2018-06-06T00:00:00.000+03:00"
},
{
"y": 20,
"y0": 31,
"month": "2018-06-07T00:00:00.000+03:00"
},
{
"y": 20,
"y0": 29,
"month": "2018-06-08T00:00:00.000+03:00"
},
{
"y": 16,
"y0": 24,
"month": "2018-06-09T00:00:00.000+03:00"
},
{
"y": 10,
"y0": 19,
"month": "2018-06-10T00:00:00.000+03:00"
},
{
"y": 5,
"y0": 23,
"month": "2018-06-11T00:00:00.000+03:00"
},
{
"y": 3,
"y0": 20,
"month": "2018-06-12T00:00:00.000+03:00"
}
],
[{
"y": 12,
"y0": 24,
"month": "2018-06-01T00:00:00.000+03:00"
},
{
"y": 14,
"y0": 25,
"month": "2018-06-02T00:00:00.000+03:00"
},
{
"y": 13,
"y0": 31,
"month": "2018-06-03T00:00:00.000+03:00"
},
{
"y": 16,
"y0": 32,
"month": "2018-06-04T00:00:00.000+03:00"
},
{
"y": 18,
"y0": 33,
"month": "2018-06-05T00:00:00.000+03:00"
},
{
"y": 19,
"y0": 29,
"month": "2018-06-06T00:00:00.000+03:00"
},
{
"y": 20,
"y0": 27,
"month": "2018-06-07T00:00:00.000+03:00"
},
{
"y": 18,
"y0": 26,
"month": "2018-06-08T00:00:00.000+03:00"
},
{
"y": 20,
"y0": 31,
"month": "2018-06-09T00:00:00.000+03:00"
},
{
"y": 17,
"y0": 29,
"month": "2018-06-10T00:00:00.000+03:00"
},
{
"y": 18,
"y0": 26,
"month": "2018-06-11T00:00:00.000+03:00"
},
{
"y": 14,
"y0": 24,
"month": "2018-06-12T00:00:00.000+03:00"
}
],
[{
"y": 8,
"y0": 24,
"month": "2018-06-01T00:00:00.000+03:00"
},
{
"y": 14,
"y0": 26,
"month": "2018-06-02T00:00:00.000+03:00"
},
{
"y": 12,
"y0": 31,
"month": "2018-06-03T00:00:00.000+03:00"
},
{
"y": 15,
"y0": 33,
"month": "2018-06-04T00:00:00.000+03:00"
},
{
"y": 18,
"y0": 37,
"month": "2018-06-05T00:00:00.000+03:00"
},
{
"y": 16,
"y0": 29,
"month": "2018-06-06T00:00:00.000+03:00"
},
{
"y": 17,
"y0": 27,
"month": "2018-06-07T00:00:00.000+03:00"
},
{
"y": 19,
"y0": 25,
"month": "2018-06-08T00:00:00.000+03:00"
},
{
"y": 25,
"y0": 30,
"month": "2018-06-09T00:00:00.000+03:00"
},
{
"y": 23,
"y0": 31,
"month": "2018-06-10T00:00:00.000+03:00"
},
{
"y": 11,
"y0": 26,
"month": "2018-06-11T00:00:00.000+03:00"
},
{
"y": 12,
"y0": 23,
"month": "2018-06-12T00:00:00.000+03:00"
}
]
]
}
var parseDate = d3.time.format("%Y-%m-%d").parse;
dataset["categories"].forEach(function(d2) {
d = new Date(d2);
});
dataset["layers"].forEach(function(d) {
d.forEach(function(d2) {
d2.month = new Date(d2.month);
});
});
n = dataset["series"].length, // Number of Layers
m = dataset["layers"].length, // Number of Samples in 1 layer
yGroupMax = d3.max(dataset["layers"], function(layer) {
return d3.max(layer, function(d) {
return d.y0;
});
});
yGroupMin = d3.min(dataset["layers"], function(layer) {
return d3.min(layer, function(d) {
return d.y;
});
});
var pWidth = document.getElementById('chart1').offsetWidth;
var margin = {
top: 50,
right: 0,
bottom: 50,
left: 100
},
width = pWidth - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain([new Date(dataset["categories"][0]), addDays(new Date(dataset["categories"][11]), 1)])
.range([0, width]);
var y = d3.scale.linear()
.domain([yGroupMin, yGroupMax])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(dataset["categories"].length)
.tickPadding(6)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([0, Infinity])
.on("zoom", zoomed);
var svg = d3.select("#chart1").append("svg")
.call(zoom)
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
svg = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer")
.attr('clip-path', 'url(#clip)');
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter().append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("x", function(d, i, j) {
var qqq = x(d.month);
var qqq2 = x(d.month) + 30 / n * j;
return x(d.month) + 30 / n * j;
})
.attr("width", 30 / n)
.transition()
.attr("y", function(d) {
return y(d.y0);
})
.attr("height", function(d) {
return height - y(d.y0 - 0)
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
})
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("text")
.attr("x", width / 3)
.attr("y", 0)
.attr("dx", ".71em")
.attr("dy", "-.71em")
.text("Min - Max Temperature (Month wise)");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'month');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d) {
if (!d.month) return null;
tooltip.select('.month').html("<b>" + d.month + "</b>");
tooltip.select('.tempRange').html(d.y + "℃ to " + d.y0 + "℃");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.month) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
function zoomed() {
console.warn("zoom");
svg.select(".x.axis").call(xAxis);
console.log(d3.event.translate[0] + " " + d3.event.translate[1]);
svg.selectAll(".chart rect").attr("transform", "translate(" + d3.event.translate[0] + ",0)scale(" + d3.event.scale + ", 1)");
}
function addDays(startDate, numberOfDays) {
var returnDate = new Date(
startDate.getFullYear(),
startDate.getMonth(),
startDate.getDate() + numberOfDays,
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds());
return returnDate;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Multi Series Span Chart (Vertical)</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="chart1" class="chart" style="width: 100%;"></div>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
</body>
<script type="text/javascript" src="main.js"></script>
</html>

plot not rendered under D3.js version 4

I am trying to port a d3 chart (which I found online) to v4 but for some reason only the axes are shown and nothing else. The code runs without any errors in the console of Chrome's developer tools and I have hit the wall as I am not an advanced d3 user. Any ideas are highly appreciated.
Here are two jsfiddles, in v3 and v4
https://jsfiddle.net/54mp286c/31/
https://jsfiddle.net/54mp286c/36/
and this is the d3 v4 code
var data = [{
"Cell_Num": 0,
"y": 3,
"x": 2
}, {
"Cell_Num": 1,
"y": 3,
"x": 6
}, {
"Cell_Num": 2,
"y": 7,
"x": 1
}, {
"Cell_Num": 3,
"y": 5,
"x": 5
}]
var margin = {
top: 10,
left: 50,
bottom: 30,
right: 10
},
width = 460 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var scale = {
x: d3.scaleLinear().range([0, width]).nice(),
y: d3.scaleLinear().range([height, 0]).nice()
};
var access = {
x: function(d) {
return d.x;
},
y: function(d) {
return d.y;
}
};
var value = {
x: function(d) {
return scale.x(access.x(d));
},
y: function(d) {
return scale.y(access.y(d));
}
};
var axis = {
x: d3.axisBottom(scale.x),
y: d3.axisLeft(scale.y)
};
var svg = d3.select(".chart").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 + ")");
svg.append("g").attr("class", "x axis");
svg.append("g").attr("class", "y axis");
svg.call(renderPlot, data);
function renderPlot(selection, data) {
updateScales(data);
selection.select(".x.axis").call(axis.x)
.attr("transform", "translate(0," + height + ")");
selection.select(".y.axis").call(axis.y);
selection
.call(renderVoronoi, data)
.call(renderPoints, data);
}
function renderVoronoi(selection, data) {
var voronoi = d3.voronoi()
.x(value.x)
.y(value.y)
.extent([
[0, 0],
[width, height]
]);
var polygons = selection.selectAll(".voronoi")
.data(voronoi(data));
polygons.enter().append("path")
.attr("class", "voronoi")
.on("mouseenter", function(d, i) {
var datum = selection.selectAll(".point").data()[i];
selection.call(renderCrosshair, datum);
})
.on("mouseleave", function(d, i) {
selection.selectAll(".crosshair").remove();
});
polygons
.attr("d", d3.line());
polygons.exit()
.remove();
}
function renderCrosshair(selection, datum) {
var lineData = [
// vertical line
[
[value.x(datum), height],
[value.x(datum), 0]
],
// horizontal line
[
[0, value.y(datum)],
[width, value.y(datum)]
]
];
var crosshairs = selection.selectAll(".crosshair.line").data(lineData);
crosshairs.enter().append("path")
.attr("class", "crosshair line");
crosshairs
.attr("d", d3.svg.line());
crosshairs.exit()
.remove();
var labelData = [{
x: -6,
y: value.y(datum) + 4,
text: Math.round(access.y(datum)),
orient: "left"
},
{
x: value.x(datum),
y: height + 16,
text: Math.round(access.x(datum)),
orient: "bottom"
}
];
var labels = selection.selectAll(".crosshair.label").data(labelData);
labels.enter().append("text")
.attr("class", "crosshair label");
labels
.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
})
.style("text-anchor", function(d) {
return d.orient === "left" ? "end" : "middle";
})
.text(function(d) {
return d.text;
});
labels.exit().remove();
}
function renderPoints(selection, data) {
var points = selection.selectAll(".point").data(data);
points.enter().append("circle")
.attr("class", "point")
.attr("cx", value.x)
.attr("cy", value.y)
.attr("r", 0)
.style("opacity", 0);
points
.transition().duration(1000)
.attr("cx", value.x)
.attr("cy", value.y)
.attr("r", 2)
.style("opacity", 1);
points.exit()
.transition().duration(1000)
.attr("r", 0)
.style("opacity", 0)
.remove();
}
function updateScales(data) {
var extent = {
x: d3.extent(data, access.x),
y: d3.extent(data, access.y)
};
scale.x.domain([extent.x[0] - 0.5, extent.x[1] + 0.5]);
scale.y.domain([extent.y[0] - 0.5, extent.y[1] + 0.5]);
}
Many thanks!

Multiple ellipses in D3 not visible with no error

A simple program for multiple ellipse I have written. The program shows no error but also no ellipse is being seen. Though i tried add multiple random colors for it. I think there is some slight mistake somewhere. Can someone help out?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
<script>
$(document).ready(function(){
//our basic data
var customData = [
{ "x": 30, "y": 30, "width": 20, "height" : 10 },
{ "x": 70, "y": 70, "width": 20, "height" : 20},
{ "x": 110, "y": 100, "width": 20, "height" : 30}
];
//Make an SVG Container
var mySVG = d3.select("svg");
//create ellipses skeleton by data
var ellipses = mySVG.selectAll("ellipse")
.data(customData)
.enter()
.append("ellipse");
//Draw the Rectangle
ellipses.append("ellipse")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("rx", function (d) { return d.width; })
.attr("ry", function(d) { return d.height; })
.attr("fill",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; });
});
</script>
</head>
<body>
<svg width="500px" height="500px"></svg>
</body>
</html>
You are appending ellipse elements twice. Here is the working snippet.
var customData = [{
"x": 30,
"y": 30,
"width": 20,
"height": 10
}, {
"x": 70,
"y": 70,
"width": 20,
"height": 20
}, {
"x": 110,
"y": 100,
"width": 20,
"height": 30
}];
//Make an SVG Container
var mySVG = d3.select("svg");
//create ellipses skeleton by data
var ellipses = mySVG.selectAll("ellipse")
.data(customData)
.enter()
.append("ellipse");
// Removed second append from here
//Draw the Rectangle
ellipses.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("rx", function(d) {
return d.width;
})
.attr("ry", function(d) {
return d.height;
})
.attr("fill", function() {
return "hsl(" + Math.random() * 360 + ",100%,50%)";
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500px" height="500px"></svg>

Categories

Resources