concentric emanating circles d3 - javascript

I have an array of equally spaced values which I am using to draw concentric circles. I want to use an emanating effect, in essence, remove the outermost circle once its value exceeds the maximum value and add a new one at the center to compensate. I am unsure about manipulation on data set to remove and add new circle.
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("body").append("svg");
var w = window.innerWidth;
var h = window.innerHeight;
var separation = Math.min(50, w/12);
var n=Math.floor((w/2)/separation);
var ellipse=new Array(n);
for(var i=1;i<=n;i++){
ellipse[i-1]=(i*separation);
}
svg.attr("width", w).attr("height", h);
var g = svg.append("g");
var e=g.selectAll("ellipse")
.data(ellipse)
.enter()
.append("ellipse")
.attr("cx", w/2)
.attr("cy", h/2)
.attr("rx",0)
.attr("ry",0)
.transition()
.duration(5000)
.attr("rx", function(d,i){return ellipse[i];})
.attr("ry", function(d,i){return ellipse[i]/5;});
loop();
function loop(){
e.transition()
.attr("rx", function(d,i){
return ellipse[i]+separation;
})
.attr("ry", function(d,i){
return (ellipse[i]+separation)/5;
})
.on("end",loop());
}
</script>

You could approach it with a remove().exit() and enter().append() selection for each ring - but essentially you always have the same number of rings on the screen. Why not just recycle the same elements? When the size hits a threshold, reset it to zero, or some other starting value?
Something along the lines of:
var scale = d3.scaleLinear()
.range(["orange","steelblue","purple"])
.domain([0,60]);
var data = [0,10,20,30,40,50,60];
var width = 200;
var height = 200;
var svg = d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r",function(d) { return d; })
.attr("transform","translate(80,80)")
.attr("fill","none")
.style("stroke-width","4")
.style("stroke",function(d) { return scale(d) });
function transition() {
// Update data, max d is 60:
data = data.map(function(d) { return d == 60 ? 0 : d + 10});
var i = 0;
// Grow circles
circles
.data(data)
.filter(function(d) { return d > 0 })
.transition()
.ease(d3.easeLinear)
.attr("r", function(d) { return d; })
.style("stroke", function(d) { return scale(d) })
.style("opacity",function(d) { return d == 60 ? 0 : 1 })
.duration(1000)
.on("end",function(){if(++i==circles.size()-1) { transition(); } });
// Reset circles where r == 0
circles
.filter(function(d) { return d == 0 })
.attr("r", 0)
.style("opacity",1)
.style("stroke",function(d) { return scale(d); });
}
transition();
<script src="https://d3js.org/d3.v4.min.js"></script>
Note that .on("end",... triggers on each element's transition end - this is why I count to see if all elements are done transitioning before running the transition function again.

Related

d3.js realtime line chart with circle

I'm trying to make a d3 realtime line chart with circle at the data point.
However, circles are gathered on the left side and it is not given to the data point.
This method is fine for static data to show circles with line chart.
chart.append('circle')
.data(data)
.attr('class', 'ciecle')
.attr("cy", line.x())
.attr("cy", line.y())
.attr("r", 5)
.attr("fill", 'blue');
However, it does not work with dynamically increasing data.
I want to move the circles with realtime line chat.
The follow code was forked from this URL
http://bl.ocks.org/KevinGutowski/131809cc7bcd1d37e10ca37b89da9630
Would you please let me how to change the code?
<svg id="chart"></svg>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script>
var data = [];
var width = 500;
var height = 500;
var globalX = 0;
var duration = 100;
var max = 500;
var step = 10;
var chart = d3.select('#chart')
.attr('width', width + 50)
.attr('height', height + 50);
var x = d3.scaleLinear().domain([0, 500]).range([0, 500]);
var y = d3.scaleLinear().domain([0, 500]).range([500, 0]);
// -----------------------------------
var line = d3.line()
.x(function(d){ return x(d.x); })
.y(function(d){ return y(d.y); });
var smoothLine = d3.line().curve(d3.curveCardinal)
.x(function(d){ return x(d.x); })
.y(function(d){ return y(d.y); });
// -----------------------------------
// Draw the axis
var xAxis = d3.axisBottom().scale(x);
var axisX = chart.append('g').attr('class', 'x axis')
.attr('transform', 'translate(0, 500)')
.call(xAxis);
var path = chart.append('path');
var circle = chart.append('circle');
// Main loop
function tick() {
// Generate new data
var point = {
x: globalX,
y: ((Math.random() * 450 + 50) >> 0)
};
data.push(point);
globalX += step;
// Draw new line
path.datum(data)
.attr('class', 'smoothline')
.attr('d', smoothLine);
// Append circles.  It should given to data point
chart.append('circle')
.data(data)
.attr('class', 'ciecle')
.attr("cy", line.x())
.attr("cy", line.y())
.attr("r", 5)
.attr("fill", 'blue');
// Shift the chart left
x.domain([globalX - (max - step), globalX]);
axisX.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.call(xAxis);
path.attr('transform', null)
.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.attr('transform', 'translate(' + x(globalX - max) + ')');
//move with line
circle.attr('transform', null)
.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.attr('transform', 'translate(' + x(globalX - max) + ')')
.on('end', tick);
// Remote old data (max 50 points)
if (data.length > 50) data.shift();
}
tick();
</script>
The coordinates of the path get repeatedly updated in the tick function (which repeatedly calls itself) using path.datum(data). You also need to update the locations of the circles on each tick using the adjusted (shifted) scale, which gets changed here:
x.domain([globalX - (max - step), globalX]);
To make the transitions smooth, you also need to update the transforms in each tick. You could update it for each circle and the path itself individually, but I just put both in a group (<g>) element and animate the whole group. Here's a working example:
http://bl.ocks.org/Sohalt/9715be30ba57e00f2275d49247fa7118/43a24a4dfa44738a58788d05230407294ab7a348

d3 projection geoMercator returns none

I'm trying to plot some cordinates on an image using d3 v4 following this Link.When i'm trying to pass my co-ordinates to the projection function it returns NAN for some of the data points. I got some help from here that javascript follows the following latitude and longitude convention but not sure how it exacty works.
This is the format of my data:
{coordinates: [60, 84],coordinates: [204, 92.4],coordinates: [117, 132.72]}
D3 code :
var el = d3.select('.js-map'),
// 150 DPI image
width = 300,
// 150 DPI image
height = 300;
var thisObj = this;
var projection = d3.geoMercator()
.scale(1)
.translate([0, 0])
console.log('projection', projection);
var path = d3.geoPath()
.projection(projection);
var map = el.append('svg')
.attr('width', width)
.attr('height', height);
map.append('image')
.attr('xlink:href', this.floorMaps[0])
.attr('width', width)
.attr('height', height);
this.floorSensorInfo.forEach((data, index) => {
var lonlat = projection(data.coordinates);
console.log('Longitude Latitude', lonlat);
I can see my data output like [2.0420352248333655, NaN]and not sure what happened exactly.
and moreover if someone can explain following the first link which i realy don't understand it would be really helpful
Exported bounds of raster image
rasterBounds = [[-122.7895, 45.4394], [-122.5015, 45.6039]]
Update:
#Andrew suggested to plot normal co-ordinates because latitude and longitude apply only to world maps. So i had pasted my below working code version now which is plotting the points on the image now.
var svg = d3.select("body")
.append("svg")
.attr("width",960)
.attr("height",500)
// image width and height in pixels, we don't want to skew this or scale this (then image units aren't straight pixels)
var imageWidth = 300;
var imageHeight = 168;
var color_hash = { 0 : ["apple", "green"],
1 : ["mango", "orange"],
2 : ["cherry", "red"]
}
function scale(coords) {
return [coords[0] * imageWidth / 100, coords[1] * imageHeight / 100];
}
svg.append("image")
.attr("width",imageWidth)
.attr("height",imageHeight)
.attr("x", 0) // could be non-zero, but we would have to shift each circle that many pixels.
.attr("y", 0)
.attr("xlink:href", this.floorMaps[0])
var data = this.floorSensorInfo
// var dataNest = d3.nest()
// .key(function (d) { return d['sensor_name']; })
// .entries(data)
data.forEach(function (d, i) {
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return (d.value)[0]; })
.attr("cy", function(d) { return (d.value)[1]; })
.attr("r", 5)
.style("fill", function(d) {
var color = color_hash[data.indexOf(d)][1]
return color;
})
svg.append('text')
.attr("x", 20+(i)*100) // space legend
.attr("y", imageHeight+20)
// style the legend
.style("stroke", function () { // Add the colours dynamically
return d['color'] = color_hash[data.indexOf(d)][1];
})
//.attr("dy", ".35em")
.text( d.sensor_name);
//.text("jjjjjjj")
})}
var svg = d3.select("body")
.append("svg")
.attr("width",960)
.attr("height",500)
// image width and height in pixels, we don't want to skew this or scale this (then image units aren't straight pixels)
var imageWidth = 300;
var imageHeight = 168;
var color_hash = { 0 : ["apple", "green"],
1 : ["mango", "orange"],
2 : ["cherry", "red"]
}
function scale(coords) {
return [coords[0] * imageWidth / 100, coords[1] * imageHeight / 100];
}
svg.append("image")
.attr("width",imageWidth)
.attr("height",imageHeight)
.attr("x", 0) // could be non-zero, but we would have to shift each circle that many pixels.
.attr("y", 0)
.attr("xlink:href", this.floorMaps[0])
var data = this.floorSensorInfo
// var dataNest = d3.nest()
// .key(function (d) { return d['sensor_name']; })
// .entries(data)
data.forEach(function (d, i) {
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return (d.value)[0]; })
.attr("cy", function(d) { return (d.value)[1]; })
.attr("r", 5)
.style("fill", function(d) {
var color = color_hash[data.indexOf(d)][1]
return color;
})
svg.append('text')
.attr("x", 20+(i)*100) // space legend
.attr("y", imageHeight+20)
// style the legend
.style("stroke", function () { // Add the colours dynamically
return d['color'] = color_hash[data.indexOf(d)][1];
})
//.attr("dy", ".35em")
.text( d.sensor_name);
//.text("jjjjjjj")
})}
javascript d3.js

Force simulation is jittery when using svg transforms to update position

JSFiddle example
I've noticed that when updating positions of svg elements in a d3-force diagram, updating the positions of elements using (in the case of circles) the cx and cy attributes is much smoother than using the transform attribute.
In the example JSFiddle, there are two separate force simulations side-by-side. The one on the left updates positions using the transform attribute:
sim_transform.on('tick', function () {
circles_transform.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
});
The one on the right updates positions using the cx and cy attributes of a circle:
sim_position.on('tick', function () {
circles_position
.attr('cx', function (d) {
return d.x;
})
.attr('cy', function (d) {
return d.y;
})
});
The simulations appear identical until they're just about to become static, at which point the one using transforms starts to jitter quite a bit. Any ideas what is causing this? Can it be fixed so that the animation remains smooth using transforms?
It seems to me that the issue you're observing (only reproducible in FireFox, as #altocumulus noted) has something to do with the way FF uses floating numbers for the translate of the transform attribute.
We can see this if we set both simulations to use integers, doing ~~(d.x) and ~~(d.y). Have a look, both will jitter:
var svg = d3.select('svg');
var graph_transform = gen_data();
var graph_position = gen_data();
var force_left = d3.forceCenter(
parseInt(svg.style('width')) / 3,
parseInt(svg.style('height')) / 2
)
var force_right = d3.forceCenter(
2 * parseInt(svg.style('width')) / 3,
parseInt(svg.style('height')) / 2
)
var sim_transform = d3.forceSimulation()
.force('left', force_left)
.force('collide', d3.forceCollide(65))
.force('link', d3.forceLink().id(id));
var sim_position = d3.forceSimulation()
.force('right', force_right)
.force('collide', d3.forceCollide(65))
.force('link', d3.forceLink().id(id));
var g_transform = svg.append('g');
var g_position = svg.append('g');
var circles_transform = g_transform.selectAll('circle')
.data(graph_transform.nodes)
.enter()
.append('circle')
.attr('r', 40);
var circles_position = g_position.selectAll('circle')
.data(graph_position.nodes)
.enter()
.append('circle')
.attr('r', 40);
sim_transform
.nodes(graph_transform.nodes)
.force('link')
.links(graph_transform.links);
sim_position
.nodes(graph_position.nodes)
.force('link')
.links(graph_position.links);
sim_transform.on('tick', function() {
circles_transform.attr('transform', function(d) {
return 'translate(' + (~~(d.x)) + ',' + (~~(d.y)) + ')';
});
});
sim_position.on('tick', function() {
circles_position
.attr('cx', function(d) {
return ~~d.x;
})
.attr('cy', function(d) {
return ~~d.y;
})
});
function id(d) {
return d.id;
}
function gen_data() {
var nodes = [{
id: 'a'
},
{
id: 'b'
},
{
id: 'c'
},
{
id: 'd'
}
]
var links = [{
source: 'a',
target: 'b'
},
{
source: 'b',
target: 'c'
},
{
source: 'c',
target: 'd'
},
{
source: 'd',
target: 'a'
}
];
return {
nodes: nodes,
links: links
}
}
svg {
width: 100%;
height: 500px;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
So, in your original code, it seems like the circles move correctly when using cx and cy, but they jump from integer to integer when using translate (or maybe half pixel, see the last demo). If the hypothesis here is correct, the reason that you just see the effect when the simulation is cooling down is because, at that moment, the movements are smaller.
Demos
Now, if we get rid of the simulation, we can see that this strange behaviour also happens with a very basic transform. To check this, I created a transition for a big black circle, using a linear ease and a very long time (to facilitate seeing the issue). The circle will move 30px to the right. I also put a gridline to make the jumps more noticeable.
(Warning: the demos below are only reproducible in FireFox, you won't see any difference in Chrome/Safari)
If we use cx, the transition is smooth:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98)
.transition()
.duration(10000)
.ease(d3.easeLinear)
.attr("cx", "230")
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
However, if we use translate, you can see the circle jumping 1px at every move:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98)
.transition()
.duration(10000)
.ease(d3.easeLinear)
.attr("transform", "translate(30,0)")
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
For you people running this in Chrome/Safari, this is how the last snippet looks like in Firefox. It's like the circle is being moved half a pixel at every change... definitely not as smooth as changing cx:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98);
var timer = d3.timer(function(t){
if(t>10000) timer.stop();
circle.attr("cx", 200 + (~~(60/(10000/t))/2));
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
As this is an implementation issue only visible in FF, it may be worth reporting a bug.

D3JS oscillating bubbles

This might be trivial to some people, but I am a newbie to D3JS.
I am trying to plot two static bubbles with opacity changing with respect to an array. I am able to plot the bubbles but I can't make their opacity change continuously. I am using transition and delay and the opacity can only change once. Here is my code sample
(function() {
var dropsize = 100;
var gapsize = 20;
var osc = [[1, 1],[0.5, 0.5],[0, 0],[0.5, 0.5],[1, 1],[0.5, 0.5],[0, 0],[0.5, 0.5]];
var radius = dropsize / 2;
var h = 100;
var w = (4 * radius + 3 * gapsize);
var svg = d3.select("#chart").append("svg");
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.style("background-color", "teal");
var circles = svg.selectAll("circle")
.data([radius, 3 * radius])
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return d + (i + 1) * gapsize;
})
.attr("cy", h / 2)
.attr("r", function(d, i) {
return radius;
})
.attr("fill", "orange")
.attr("class", "droplet")
.attr("id", function(d, i) {
return "c_" + (i + 1);
});
d3.select("#c_1")
.data(osc)
.transition().delay(function(d, i) {
return i * 1000;
})
.duration(1000)
.attr("opacity", function(d) {
return d[0]
});
})();
See the Pen Bubble Chart with D3.js using Realtime Data
If by "continuously" you mean that you want to run the transition infinitely, use on("end") to call the transition function again.
Here is an example:
var toggle;
var data = [0, 1];
transition();
function transition() {
toggle ^= 1;
d3.select("circle")
.transition()
.duration(1000)
.style("opacity", data[toggle])
.on("end", transition);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
<circle cx="100" cy="100" r="50"></circle>
</svg>
I assume by continuously you mean smoothly transition rather than switch immediately from one opacity state to the next, as opposed to repeating the transition.
You first need to set an initial opacity on the circles when you create them:
.attr("opacity", 0)
And then use d3.selectAll rather than d3.select, or better your variable circles
...
circles
.data(osc)
.transition()
.delay(function(d,i){ return i*1000; })
.duration(1000)
.attr("opacity",function(d){ return d[0] });

Inserting data (bar charts and weather info) into SVG Circles

I'm trying to create a visual effect (using D3.js and json) where 4 small circles will pop up once I click on the big yellow circle. I want to make sure that ALL of the circles will present pieces of information that I'm trying to assign to each and every one of them. I plan to have:
-The 1st big yellow circle to present the weather (sunny, mostly cloudy, etc)
-2 small circles to present weather info by word
-2 small circles present a D3 bar chart that I made, along with some weather info by word
(I have all of the info separated by spaces and comments)
However, my problem is (for the lack of a better explanation) that I am just stumped! I have no idea how to make that happen. I would really appreciate it if I can get help from you guys. Here's my code (HTML and JS):
var h = 2000;
var w = 2000;
var xGrid = 300;
var yGrid = 300;
var radius = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var shape = svg.append("circle")
.attr("cx", xGrid)
.attr("cy", yGrid)
.attr("r", radius)
.style("fill", "yellow");
shape.on("click", function(){
var circle1 = svg.append("circle")
//.attr("cx", (xGrid-radius/2)+0)
//.attr("cy", (yGrid-radius/2)+0)
.attr("cx", xGrid - radius/2)
.attr("cy", yGrid - radius/2)
.attr("r", radius/2)
.style("fill", "red");
var circle2 = svg.append("circle")
//.attr("cx", (xGrid-radius/2)+10)
//.attr("cy", (yGrid-radius/2)+10)
.attr("cx", xGrid + radius/2)
.attr("cy", yGrid - radius/2)
.attr("r", radius/2)
.style("fill", "blue");
var circle3 = svg.append("circle")
// .attr("cx", (xGrid-radius/2)+20)
// .attr("cy", (yGrid-radius/2)+20)
.attr("cx", xGrid - radius/2)
.attr("cy", yGrid + radius/2)
.attr("r", radius/2)
.style("fill", "green");
var circle4 = svg.append("circle")
// .attr("cx", (xGrid-radius/2)+30)
//.attr("cy", (yGrid-radius/2)+30)
.attr("cx", xGrid + radius/2)
.attr("cy", yGrid + radius/2)
.attr("r", radius/2)
.style("fill", "purple");
});
<!-- ///////////////////////////////////////////////////////////////////////////// /////////////////
///////////////////////////////(END) Circle Pop-up (END)/////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////-->
</script>
<!--///////////////////////////////////////////////////////////////////////////// ////////////////////////
///////////////////////////(START) Info for circles to present (START)////////////////////////////////
///////////////////////////////////////////////////////////////////////////// //////////////////////////////-->
<!--/////Main Circle display/////////-->
<p id="w"></p><p id="main"></p>
<!--//////Circle 1 (upper left corner) display///////////-->
<p id="rh"></p><p id="c1a"></p>
<!--///////Circle 2 (upper right corner) display//////////-->
<p id="ws"></p><p id="c2a"></p>
<p id="wd"></p><p id="c2b"></p>
<p id="we"></p><p id="c2c"></p>
<p id="wm"></p><p id="c2d"></p>
<!--////////Circle 3 (lower left corner) display/////////-->
<p id="pti"></p><p id="c3a"></p>
<p id="ptc"></p><p id="c3b"></p>
<p id="df"></p><p id="c3c"></p>
<p id="dc"></p><p id="c3d"></p>
<!--///////Circle 4 (lower right corner) display//////////-->
<p id="hif"></p><p id="c4a"></p>
<p id="hic"></p><p id="c4b"></p>
<p id="sr"></p><p id="c4c"></p>
<p id="uv"></p><p id="c4d"></p>
<script type = "text/javascript">
var dataForMainCircle = '{"weather": "Mostly Cloudy"}';
var mcDis= JSON.parse(dataForMainCircle);
var weather = "weather: ";
document.getElementById("w").innerHTML = weather;
document.getElementById("main").innerHTML = mcDis.weather;
/////////////////////////////////////////////////////////////////////////////////
////////////Setup for display of 1st circle info///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
var dataForCircle1b = '{"relative_humidity": "92%"}';
var relativeHum = "Relative Humidity: ";
var c1Dis = JSON.parse(dataForCircle1b);
d3.json("js/tempGraph.json", function (data) {
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) {return d.temp * 10; })
.attr("height", 48)
.attr("y", function (d,i) {return i * 50; })
.attr("fill", "red");
canvas.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("fill", "white")
.attr("y", function (d,i) {return i * 50 + 24; })
.text(function (d) {return d.temp; })
})
document.getElementById("rh").innerHTML = relativeHum;
document.getElementById("c1a").innerHTML = c1Dis.relative_humidity;
/////////////////////////////////////////////////////////////////////////////////////////
/ ////////////////////Setup for display of 2nd circle info////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
var dataForCircle2 = '{"wind_string": "Calm", "wind_dir": "SW", "wind_degrees": 229, "wind_mph": 2}';
var c2Dis = JSON.parse(dataForCircle2);
var windCon = "Wind Condition: ";
var windDir = "Wind Direction: ";
var windDeg = "Wind Degree: ";
var windMph = "Wind (Miles Per Hour): "
document.getElementById("ws").innerHTML = windCon;
document.getElementById("c2a").innerHTML = c2Dis.wind_string;
document.getElementById("wd").innerHTML = windDir;
document.getElementById("c2b").innerHTML = c2Dis.wind_dir;
document.getElementById("we").innerHTML = windDeg;
document.getElementById("c2c").innerHTML = c2Dis.wind_degrees;
document.getElementById("wm").innerHTML = windMph;
document.getElementById("c2d").innerHTML = c2Dis.wind_mph;
///////////////////////////////////////////////////////////////////////////// //////////////////////////////////
//Setup for display of 3rd circle info/////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////
var dataForCircle3 = '{"precip_today_in": "0.00", "precip_today_metric": "0"}';
var c3Dis = JSON.parse(dataForCircle3);
var predate = "Today's Precipitation: ";
var prem = "Precipitation Metric: ";
//var dewF = "Dewpoint-F: ";
//var dewC = "Dewpoint-C: ";
document.getElementById("pti").innerHTML = predate;
document.getElementById("c3a").innerHTML = c3Dis.precip_today_in;
document.getElementById("ptc").innerHTML = prem;
document.getElementById("c3b").innerHTML = c3Dis.precip_today_metric;
//document.getElementById("df").innerHTML = dewF;
//document.getElementById("c3c").innerHTML = c3Dis.dewpoint_f;
d3.json("js/dewGraph.json", function (data) {
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) {return d.dewpoint * 10; })
.attr("height", 48)
.attr("y", function (d,i) {return i * 50; })
.attr("fill", "white");
canvas.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("fill", "white")
.attr("y", function (d,i) {return i * 50 + 24; })
.text(function (d) {return d.dewpoint; })
})
//document.getElementById("dc").innerHTML = dewC;
//document.getElementById("c3d").innerHTML = c3Dis.dewpoint_c;
<!--//////////////Setup for display of 4th circle display////////////////////-->
var dataForCircle4 = '{"heat_index_f": "NA", "heat_index_c": "NA", "solarradiation": "--", "UV": "0"}';
var c4Dis = JSON.parse(dataForCircle4);
var heatF = "Heat Index-F: ";
var heatC = "Heat Index-C: ";
var sunR = "Solar Radiation: ";
var ultraV = "UV: ";
document.getElementById("hif").innerHTML = heatF;
document.getElementById("c4a").innerHTML = c4Dis.heat_index_f;
document.getElementById("hic").innerHTML = heatC;
document.getElementById("c4b").innerHTML = c4Dis.heat_index_c;
document.getElementById("sr").innerHTML = sunR;
document.getElementById("c4c").innerHTML = c4Dis.solarradiation;
document.getElementById("uv").innerHTML = ultraV;
document.getElementById("c4d").innerHTML = c4Dis.UV;
d3.json("js/tempGraph.json", function (data) {
var canvas1 = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas1.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) {return d.temp * 10; })
.attr("height", 48)
.attr("y", function (d,i) {return i * 50; })
.attr("fill", "red");
canvas1.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("fill", "white")
.attr("y", function (d,i) {return i * 50 + 24; })
.text(function (d) {return d.temp; })
})
d3.json("js/dewGraph.json", function (data) {
var canvas2 = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas2.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) {return d.dewpoint * 10; })
.attr("height", 48)
.attr("y", function (d,i) {return i * 50; })
.attr("fill", "blue");
canvas2.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("fill", "white")
.attr("y", function (d,i) {return i * 50 + 24; })
.text(function (d) {return d.dewpoint; })
})
</script>
</body>
</html>
Keep in mind, this program is sort of a prototype. My main concern is getting the info assigned for the circles INSIDE of them. If you guys found any errors/mix-ups in the code, feel free to notify me. Thank you!!
Ok, as promised, an example. It doesn't look super cool, but at least you will get the picture. If you have more questions, please shoot! Here goes:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="donut.js" type="text/javascript"></script>
<style>
body{
background-color:black;
}
#container {
position:relative;
display:inline-block;
width:100%;
}
.row{
position:relative;
display:inline-block;
width:100%;
text-align:center;
}
#chart{
width:60%;
position:relative;
display:inline-block;
}
text{
font-size:1.4em;
}
</style>
</head>
<body>
<div id="container">
<div class="row">
<div id="chart">
</div>
</div>
</div>
<script>
var data = [
{"type":"weather", "status":"sunny"},
{"type":"humidity", "status":"high"},
{"type":"temperature", "status":"23°"},
{"type":"pressure", "status":"1040 hpa"},
{"type":"wind", "status":"East"},
];
var chartWidth = 500;
var chartHeight = 500;
/* Adding the svg drawing canvas by selecting the element that will contain the svg. put it in a var,
as it is a d3 selection. We can reuse this selection. Remember, when chaining, you will get returned the
element you last appended, in this case the svg.
*/
var svg = d3.select("#chart")
.append("svg")
.attr({ // you can put attributes in a javascript object, i like this notation better.
width:chartWidth,
height:chartHeight
});
/* Here I am going to add the circles. With SVG elements, you cannot draw inside other elements. There are only 2 elements
which can contain other elements (as far as I know) and that is the SVG element itself and the g element. So if you want
to give the impression that the elements are inside one another, you need to make them overlap. So if I add a circle and then
add text with coordinates that match the circle, the text will overlap the circle, giving the impression it is inside it.
*/
var circles = svg.selectAll("circle")
.data(data) //binding the data. I want 5 circles for my 5 pieces of data
.enter()
.append("circle")
.attr({
cx:function(d,i){ //when doing the append on a d3 selection, you are iteration over each element!
/* I will use the index (i) to 'identify' the pieces of data and to hardcode their x central point positions */
if(i == 0) {
return chartWidth/2;
}
if(i == 1) {
return chartWidth/5;
}
if(i == 2) {
return chartWidth *(2/7);
}
if(i == 3) {
return chartWidth *(5/7);
}
if(i == 4) {
return chartWidth * (4/5);
}
},
cy:function(d,i){ //when doing the append on a d3 selection, you are iteration over each element!
/* I will use the index (i) to 'identify' the pieces of data and to hardcode their y central point positions */
if(i == 0) {
return chartHeight/2;
}
if(i == 1) {
return chartHeight *(3/5);
}
if(i == 2) {
return chartHeight *(4/5);
}
if(i == 3) {
return chartHeight *(4/5);
}
if(i == 4) {
return chartHeight * (3/5);
}
},
r:function(d,i) { /* the radius is in function of the type. The first one (weather) should be the biggest one */
if(d.type === "weather") {
return 200;
}
else{
return 75;
}
},
fill:"yellow",
stroke:"black"
});
/* Now i'll append the text as last, so it overlaps nicely with the circles. For positioning, i ll have to reuse the x and y functions
from the circles. I want the text to be positioned at the center of the cirkels.
*/
var texts = svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d){ return d.status})
.attr({
x:function(d,i){
/* So I used the same positioning for the text as for the center points of the circles.
you should realize that the text really starts at the middle of the circles. So you
should substract a bit from the x position to get them nicely in the middle. I aint going
for that trouble, its just an example.
*/
if(i == 0) {
return chartWidth/2;
}
if(i == 1) {
return chartWidth/5;
}
if(i == 2) {
return chartWidth *(2/7);
}
if(i == 3) {
return chartWidth *(5/7);
}
if(i == 4) {
return chartWidth * (4/5);
}
},
y:function(d,i){ //when doing the append on a d3 selection, you are iteration over each element!
/* I will use the index (i) to 'identify' the pieces of data and to hardcode their y central point positions */
if(i == 0) {
return chartHeight/2;
}
if(i == 1) {
return chartHeight *(3/5);
}
if(i == 2) {
return chartHeight *(4/5);
}
if(i == 3) {
return chartHeight *(4/5);
}
if(i == 4) {
return chartHeight * (3/5);
}
}
});
</script>
</body>
</html>
I did not add the function to click on the first circle to show the others. I could if you want me to though, but I felt like this example already has enough stuff in it to learn from.

Categories