Suppose we wanted to make a list-like visual. Setting the y logic for the circles can be as simple as:
var data = [0,1,2,3,4,5,6,7,8,9];
var yScale = d3.scaleLinear()
.range([height,0])
.domain([0,9]);
svg.selectAll(null)
.data(data)
.enter()
.append('circle')
.attr('cy', function(d) { return yScale(d) })
.attr('cx', 100)
.attr('r', 10)
.style('fill', "#a6a6a6");
However, suppose we wanted to go for some style points and arrange the circles not in a blocky / tabular arrangement but rather arrange them about a circle or arc. I had this result in mind (only concerned with the outer circles):
While I think d3 does have trigonometric functions, I have never seen them used in pixel coordinates. I'd imagine the pseudo-code to be something like:
var semiCircleScale = d3.?????
.range([250 degrees, 110 degrees])
.domain([0,9]);
svg.selectAll(null)
.data(data)
.enter()
.append('circle')
.attr('cy', function(d) { return semiCircleScale(d) })
.attr('cx', 100)
.attr('r', 10)
.style('fill', "#a6a6a6");
Question
Is anyone familiar with using circle / arc scales for use with x,y logic for appending shapes? Or is there an easier/less-math-intensive way?
So the idea is to create 2 different path of arc and then calculate the circumference and place the circles along with.
d3.svg.arc()
.append("path")
.attr("d", arc1)
Here is a fiddle link with minimum code to establish the idea
https://jsfiddle.net/Dibyanshu/g03p6sxj/
Related
I am trying to convert a bubble chart from d3v3 to v4. Running into x,y,d missing variables?
In this version -- a rect is applied to the svg - and then a circle is cut -- so its like an inverse bubble chart.
I am keen to work out a set radius for the chart as a maxium -- if it should act like a score between 0 and 100? What kind of math to apply that a max radius has been reached to signify that the value is very big?
I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd
//version 3
https://jsfiddle.net/8ag1vf6e/1/
//current version 4
https://jsfiddle.net/d56g9r0y/
// filters go in defs element
var defs = innversebubble.append("defs");
var mask = defs.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.style("fill", "white")
.style("opacity", 1);
var invisiblebubble = mask.append("circle")
.data(data);
//create a fixed bubble first
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", function(d) {
return d.value - 20;
});
//now mask the fixed circle
var masker = defs.append(function() {
return mask.node().cloneNode(true)
})
.attr("id", "myMaskForPointer")
.select("rect")
.style("fill", "white")
.style("opacity", 1);
invisiblebubble
.attr("r", 10);
//apply the rest of the chart elements
var rect = innversebubble
.attr("class", "series")
.append("g")
.attr("transform", "translate(0,0)")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("mask", "url(#myMask)")
.style("fill", backcolor)
.style("opacity", backopacity);
//animate this circle
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.transition()
.duration(1800)
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
latest jsfiddle - 15th June -- needs fixing
https://jsfiddle.net/xmrtahns/
"I am keen to work out a set radius for the chart as a maxium -- if it should act like a score between 0 and 100? What kind of math to apply that a max radius has been reached to signify that the value is very big?
I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd"
I've fixed the conversion and the data source - but still need issues to resolve.
var backcolor = $this.data("color");
var backopacity = $this.data("opacity");
var width = $this.data("width");
var height = $this.data("height");
var data = [{
"label": $this.data("label-name"),
"centralLabel": $this.data("central-label"),
"xPer": $this.data("displace-left"),
"yPer": $this.data("displace-top"),
"value": $this.data("bubble-value")
}];
http://jsfiddle.net/hLymw8et/2/
--I am keen to work out a set radius for the chart as a maximum -- if it should act like a score between 0 and 100?
--What kind of math to apply that a max radius has been reached to signify that the value is very big?
--I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd –
I have some circles I want to append to a radial time series chart to indicate key events. Equivalent block here.
static picture:
The code for the circles:
var eventCircles = g.selectAll('.eventCirc')
.data(eventData)
.enter()
.append('circle')
.attr('class','eventCirc')
.attr('cx', function(d) { return x(d.date); })
.attr('cy', function(d) { return y(0)})
.attr('r', 5)
.style('fill', "#003366");
The y(0) scale seems to work fine, because the units are both in pixels, but I can't figure out how to convert degrees to pixels for use with cx -- which is a required attribute for a circle.
The scales are set up as so:
var x = d3.scaleTime()
.range([0, fullCircle]);
var y = d3.scaleRadial()
.range([innerRadius, outerRadius]);
Question
How can I use d.date in conjunction with the x scale to give me a pixel coordinate for the cx attribute (and not simply a degree/radian)?
You need a bit of trigonometry here. Given the specific bl.ocks you linked, this is the math you need:
eventCircles.attr('cx', function(d) {
return y(d.Close) * -Math.sin(x(d.Date) + Math.PI)
})
.attr('cy', function(d) {
return y(d.Close) * Math.cos(x(d.Date) + Math.PI)
})
In the bl.coks you linked, Close is the y value and Date is the x value. Change them according to your data.
Here is the forked bl.ocks: https://blockbuilder.org/GerardoFurtado/16adc1bb5677adfa501b3a03b3637d75
I'm trying to edit the data of created circles in D3. Below my code is pasted of me creating a lot of circles based on some data from graphData.
Supposed I'd want to re-arrange my circles Y position with a new dataset, by transitioning them to their new destinations. How would perform this task? I've tried using attr.("cy", function(d){return yScale(parseFloat(d))} ) to update my Y-coordinates by adding data(graphData[i], function(d){return d;}) with my new data, but this does not work.
You can take a look at my JSFiddle: http://jsfiddle.net/RBr8h/1/
Instead of the for-loop in the following code I've created circles on 2 ticks of my X-axis. I have 3 sets of data and I've used to of them in the example in the fiddle. I'd like to able to use the 3rd dataset instead of the 2 first ones on both circles.
var circle;
for(var i = 0;i < graphData.length;i++){
circle = SVGbody
.selectAll("circle")
.data(graphData[i], function(d){return d;})
.enter()
.append("circle")
.attr("cx",xScale(0))
.attr("cy", yScale(minAxisY))
.attr("r",4)
.style('opacity', 0)
.transition()
.duration(1000)
.attr("cx", function(d){
return spreadCircles(i);
})
//.attr("cy", function (d, i){ return yScale(i); })
.style('opacity', 1)
.transition()
.duration(1500)
.attr("cy", function(d){return yScale(parseFloat(d))} );
Thank you for your help in advance!
To put some flesh on Lars comment, here is a FIDDLE leveraging the enter/update/exit pattern to help you out. I have altered and simplified your code (and data) just enough to demonstrate the principle.
function updateCircles(dataset,color) {
var circle = SVGbody
.selectAll("circle")
.data(dataset, function(d) { return d; });
circle
.exit()
.transition().duration(750)
.attr("r", 0)
.remove();
circle
.enter()
.append("circle");
circle
.attr("cx",function(d){return xScale(100);})
.attr("cy",function(d){return yScale(parseFloat(d))})
.attr("r",0)
.transition().duration(1500)
.attr("r",5)
.style("fill", color);
};
Update fiddle with data keyed off by index...so, circles just have their position updated.
I wanted to create a doughnut chart with d3.js and I want to put a navigation button just exactly on the middle of it, maybe when clicked shrinks the whole chart into a smaller version (expand probably). But that is not how complex my question is, but if you can find an example that probably exactly what I wanted to have, its better.
The question now is just position a circle, I don't know if there is a better alternative for it, but this is how it goes.
var height=800,
width=800;
var data = [10,50,80];
var color = d3.scale.ordinal()
.range(["red", "blue", "yellow"]);
// the graph
var radius=300;
var canvas = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var group = canvas.append("g")
.attr("transform", "translate(300,300)");
var arc = d3.svg.arc()
.innerRadius(100)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function(d){
return d;
});
var arcs = group.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.attr("fill", function(d){
return color(d.data);
});
canvas.append("g")
.attr("class", "collapse")
.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 100);
I just a did a dirty append of circle, because I don't want to go on, if there is a better way to do it, that is why I asked. How would one make it to the center, and if you are to generous, how to add events on it, probably using on, and then scale it down to about 100px and make it the button itself, so when toggled again, it collapses
EDIT
Guess I'm a bit asking to much, how about:
Center the button without hard coding 300px to it? and on your opinion , would an svg circle can do fine as a button?
I would like to add one simple arc in the chart section like a circle:
vis.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 50)
.attr("cy", 50);
The provided examples of D3 are working with data properties but i would like to see it without any underlying data.
D3 uses a path generator for arcs. If you don't want to data-drive your arc just define the arc generator and add some methods...
var arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(45 * (Math.PI/180)) //convert from degs to radians
.endAngle(3) //just radians
vis.append("path")
.attr("d", arc)
.attr("transform", "translate(50,50)")
You can see a demo here: http://jsfiddle.net/h9XNz/