I created a scatter plot using D3.js that updates every 20 seconds. It also pans and zooms. The problem is the data lags behind the axis during the pan. I've looked for examples of a similar implementation but all I can find are ones that either do zoom/pan or do intervals, not both. I can't find the source of the problem. A simplified demo of my code can be found here: http://jsbin.com/yurik/1/edit. Any help is appreciated.
The synchronization issue comes from the fact that you are using a transition to move the circles and not using a transition to update the x-axis. Here's the relevant snippet from the draw function:
circles.transition()
.attr("cx", function(d) { return x(dateFn(d)) })
.attr("cy", function(d) { return yValueFn(d) });
svg.selectAll("g.x.axis").call(xAxis);
Because D3 has a default transition duration of 250 milliseconds, the circles are lagging behind the axis, which is updated instantly. You can synchronize the two by reducing the transition duration to 0 like this:
circles.transition().duration(0)
That should make the x-axis and circles move synchronously.
Related
I have created a zoomable sunburst with the reference from the following website. http://bl.ocks.org/mbostock/4348373
The problem is I have a lot of arcs in the final level i.e the outermost ring (nearly 2000 arcs) and this is slowing the sunburst transitions on click.
One way through which I am trying to fasten the process is show the outermost arcs only when the user dives into the sunburst (clicks on any of the sub arcs). If the outermost arc is fourth concentric circle. Show that only when user selects levels 2/3.
I created the initial dataset to have size set to 0 for the outermost arcs. And on click I wrote a function to set the size to 1. However it is not working. Below is the link http://jsfiddle.net/Claw_22/1400rdu0/6/
function sizeFunc(data){
if (!data.children) {
if (data.level=="3") {
data.size="1";
}
}
else {
for (i=0;i<data.children.length;i++) {
sizeFunc(data.children[i]);
}
}
}
Kindly let me know how we can achieve this. (Alternate solutions to achieve faster performance are also helpful.)
You can change the transition duration to a min level in click function. Something like following
function click(d) {
path.transition()
.duration(100) //sets the delay in transition
.attrTween("d", arcTween(d));}
I'm trying to make a timeline where the:
circle radius = visit duration
x-position = time of visit
.attr('cx', function(d,i) { /* insert code here */ } )
basically what I want is tell d3 to align the circle to "startDate", however there's a problem with this as circles with bigger radii will shift towards the left, making it look inaccurate since it's aligned to the center.
what are possible solutions for this?
here's the code: http://jsfiddle.net/jg4v1ymx/2/
edit - instead of the radius: if data is bigger, tell d3 to increase circle size by diameter? the problem is I don't want big radii circles overlap with circles in nearby dates
You just need to pass the x scale the date, as in:
.attr('cx', function(d,i) {
return x(d.date);
} )
You also need to make sure that you have set the domain before you do this, so move the x.domain(/*stuff*/) above the chart1 line.
You can see a working fiddle
There is a popular library in d3.js that provides a bullet chart implementation. I am in the process of making a small amendment to the default behaviour of this chart.
A bullet chart consists of one or more markers, parallel lines to identify targets, and I wish to programatically make one of the markers slightly shorter in length than the other. I'm pretty close to the solution and I have shared my work at Bullet Fiddle. To see my issue you have to hit the Year and Quarter buttons and notice how that the line shrinks and grows and then shrinks again. I want it to remain at the shorter length.
It seems that the default behaviour of the bullet is trigged at each update which is causing it to reset the marker to it's original size. I would love some help to understand how I can override this default behaviour and keep the line at a custom size.
This is a sample of the code that I use to update the marker:
d3.selectAll(".bullet .marker.s1").attr("y1", 10).attr("y2", 35);
This is the code in the library that is causing your changes to be overwritten:
marker.transition()
.duration(duration)
.attr("x1", x1)
.attr("x2", x1)
.attr("y1", height / 6) // the y1 and y2 values get updated here
.attr("y2", height * 5 / 6);
So the easiest way would just be to fork the library and delete the couple of lines. Otherwise, I didn't see that the marker definitions get exposed as part of the chart for you to remove the transition.
I have a application where I draw a world map with D3 and I use latitude and longitude data from a different source to plot them on the map. Currently what I learnt from lot of google'ing is that i can plot points by appending "circle" to to the SVG, which works fine for first 15 to 20 seconds after my web page is opened, later everything gets too slow and sloppy.
I am not sure how to keep the performance of the page decent and not add a new DOM element for every single circle I append with SVG. Do I need to use some other technology to achieve this ? Please advice.
My code looks like below and I call this like 500 times every 5 seconds.
function draw_point(lat, lon, keyword) {
var x = projection([lon, lat])[0];
var y = projection([lon, lat])[1];
svg.append("circle")
.attr("cx", x)
.attr("cy", y)
.attr("r", 0.5)
.style("fill", "gold");
svg.append("text")
.text(keyword)
.attr("x", x)
.attr("y", y)
.style("fill", "gold")
.style("font-size", "10px")
.transition()
.duration(40)
.style("opacity", 0)
.remove();
}
To give a bit more context, I am trying to do something like this site http://tweetping.net/ In this page I see that new DOM element is not being added for every dot placed in the map, I am looking for something similar.
The page which you mentioned uses canvas element and not svg or d3.js. You might want to look into
fabricjs
paperjs
kinectjs
Additional clarification of #VivekKumarBansal's suggestion: The general rule is that SVG slows down as more elements are added, but making images larger or smaller doesn't affect speed. Canvas doesn't slow down as more elements are added, but increasing size does slow it down. d3.js can be used with Canvas, although it seems to be more common to use it with SVG.
I have been experimenting with a simple d3 google analytics-style area graph demo. I'd like to make it stretch to the full width of its container, which I have managed to do. However the little circles are of course stretching out of shape too. I'd like their positions to be responsive, but not their dimensions (so they remain circular).
Fiddle link: http://jsfiddle.net/46PfK/2/
I'm trying to use the SVGPanUnscale.js script. I have tried calling it with unscaleEach('.dot'); and [].forEach.call($('.dot'),unscale); but neither appear to do anything.
This example is responsive in a similar way to mine and uses the script to 'unscale' the axis labels: http://meloncholy.com/static/demos/responsive-svg-graph-1/
This example also uses circle elements:
http://phrogz.net/svg/scale-independent-elements.svg
I looked at solutions involving the css attribute:
circle {
vector-effect: non-scaling-stroke;
}
which created a circular stroke on an ellipse - weird.
A CSS solution would be preferable to a JS one, provided it works across browsers.
Any suggestions?
Thanks to #leMoisela for pointing me in the right direction. I fixed my issue nicely using JS to redraw the graph on resize:
http://jsfiddle.net/46PfK/4/
window.onresize = function(e){
draw_graph();
};
There's a good example on resizing with D3 https://blog.safaribooksonline.com/2014/02/17/building-responsible-visualizations-d3-js/
After you update your scales, only thing left to resize your circles would be something like this:
/* Force D3 to recalculate and update the points */
svg.selectAll('circle')
.attr('cx', function (d) { return xScale(d.x); })
.attr('cy', function (d) { return yScale(d.y); })
.attr('r', 4);