Description: I have a multiple line chart with controls to filter which lines show, so lines are entering and exiting.
Desired effect: I want to transition the line to be exactly where the x-axis is (flattening it to a horizontal line the width of the x axis) before it disappears.
What I'm trying:
var moveBottomLeft = `M0,${this.height - margin.bottom}`;
var lineBottomRight = `L${this.width - margin.right},${this.height-margin.bottom}`;
path.exit().transition().duration(DURATION).attr('d', moveBottomLeft+lineBottomRight).remove();
What happens:
All of the line disappears besides the first section.
That small section of line expands to the width of the x axis, and translates down to where it is.
Instead, I would like the whole line to transform (not just that first section). How can I achieve this?
Figured it out: use d3.svg.line(), but set y to just return the height of the chart. (my code looks different, but I think this would be close)
path.exit().transition().attr('d', function() {
return d3.svg.line()
.x(function(d){return d})
.y(function(d){return chartHeight})(lineData)
})
.remove()
Related
I am new to d3v4 and working on a chart where i need to show little rectangle on certain date matching to its title on yaxis. The problem i am facing is rectangles in the chart area not drawing equal to the yaxis point labels, i have tried changing the y value by hardcoding, it works fine but the point is the number of data object will change in real time like it could be any number of objects in an array. Here is the plunker
To draw the graph dynamically with limited data objects i've created few buttons on top of chart so that rectangles in the chart can draw equal to y-axis labels.
Any help is much appreciated.
You are using a band scale: that being the case, you should not change the y position, which should be just...
.attr('y', function(d) {
return yScale(d.title);
})
.. and you should not hardcode the height: use the bandwidth() instead:
.attr('height', yScale.bandwidth())
The issue now is setting the paddingInner and paddingOuter of the scale until you have the desired result. For instance:
var yScale = d3.scaleBand().domain(data.map(function(d) {
return d.title
}))
.range([height - 20, 0])
.paddingInner(0.75)
.paddingOuter(.2);
Here is the plunker with those changes: https://plnkr.co/edit/ZxGCeDGYwDGzUCYiSztQ?p=preview
However, if you still want (for whatever reason) hardcode the height or the width of the rectangles, use a point scale instead, and move the y position by half the height.
I am using chart.js to try to create a timeline of events relative to current date.
The horizontal bar chart is close but would like to show only the tips of the bars eg as points which would pretty much be a horizontal line chart.
I have shown my horizontal bar chart along with a mock-up of what it would look like as horizontal line chart.
Is this possible with chart.js ?
You first need to know that every information that you can edit about the chart is stored in the variable containing your chart (called myChart usually, but my2Bar in your fiddle).
If you want to globally change the graph, you will need to edit attributes in myChart.config.options.
If you want to change a specific chart, you will need to edit attributes in myChart.config.data.
In this case, you need to change a specific chart (which is the horizontal bar).
If you happen to check the logs of your graph, and go very deep in the config, you will finally see that bars in your chart are drawn using attributes stored in myChart.config.data.datasets[0]._meta[0].data[n]._model (n being the nth rectangle drawn, top to bottom).
Some attributes you can find there :
base : The X position where the rectangle is starting to be drawn (0 in your xAxe for instance).
x : The rectangle is being drawn until this X position.
height : The height of the drawn rectangle.
and so on ...
To edit these values, you just need to loop in your different rectangles (the n in the above path).
But you just can't do it manually on the config of your variable. If you do this, it won't work since your chart is responsive (on resize, it will redraw the chart using the former options).
What you must use are Chart.js plugins.
Plugins let you handle all the events that are triggered while creating, updating, rendering your graph.
Then, in your beforeRender event (triggered after the initialisation, but before the drawing), you need to loop in your different rectangles to edit the values to affect how they will be drawn :
beforeRender: function(chart) {
for (var i = 0; i < chart.config.data.datasets[0]._meta[0].data.length; i++) {
// Change both `3` values to change the height & width of the point
chart.config.data.datasets[0]._meta[0].data[i]._model["base"] = chart.config.data.datasets[0]._meta[0].data[i]._model["x"] + 3;
chart.config.data.datasets[0]._meta[0].data[i]._model["height"] = 3;
}
}
Here is a jsFiddle with the final result.
Unfortunately, I wasn't able to make round dots, instead of squared ones.
Update :
I have also made another jsFiddle where all the dots are linked together which makes it look like it is a horizontal line chart (can be improved of course, but it is a good start).
I'm coding a dimple based bubble chart, which for some z-values removes a bubble and draws a big red X instead, which is an svg path created by line interpolation like this:
var points = [{"x":x-edgeSize,"y":y+edgeSize},
{"x":x,"y":y},
{"x":x+edgeSize,"y":y-edgeSize},
{"x":x,"y":y},
{"x":x-edgeSize,"y":y-edgeSize},
{"x":x,"y":y},
{"x":x+edgeSize,"y":y+edgeSize},
{"x":x,"y":y}];
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
var path = graphSelection.append("path").attr("d",lineFunction(points))
.attr("stroke",color)
.attr("stroke-width",lineWidth);
Now, I want it to be responsive and I followed dimple's example for responsive charts:
Dimple - Responsive sizing and now all the sizes and bounds are by % and I'm calling draw on resize:
this.chart.draw(this.delay,true);
The problem is that the red Xs don't move by themselves, obviously.
So I tried to move it independently on resize, but I don't know the right coordinates until the transition ends - which makes it a 2 step transition.
Will adding the X-path to series.shapes help? will it move along with the other bubbles?
Is there a standard way of doing this?
Thanks
In my NVD3 chart here, I have shifted the X-axis label downward so as to go with the vertically aligned dates. For that I did:
xTicks.select('.nv-axislabel').attr("y", 90); // line # 81 in JS
Now the problem is that if I hide any of the series using the control on the top right, this X-axis label restores to its original position which is behing the dates.
How do I get it to stay at the new position, unaltered?
jsFiddle
Somewhat of a dirty solution, but may be good enough:
After changing the y attribute of the label, remove the class which is used by d3 internally to pick the label and reset its attributes:
xTicks.select('.nv-axislabel')
.attr("y", 90)
.classed({'nv-axislabel':false});
Then, as it would appear d3 just creates a new label in the unwanted position, you can add this to the CSS file:
.nv-x .nv-axislabel {
display:none;
}
I added it as a rule because doing it programatically (using .style()) takes too long and you can see it flicker.
FIDDLE
If you update your NVD3 library, to version 1.1.11b
You can use the in-built feature of rotating the labels. Try this :
chart.xAxis
.tickPadding(-5).rotateLabels(-90);
Change the x attribute of .tick major > text to 10 to move the position a bit lower.
Then you will NOT need the following code :
// translate and rotate x-axis ticks
var xTicks = d3.select('.nv-x.nv-axis > g').selectAll('g');
xTicks.selectAll('g > .tick > text')
.attr('transform', function(d, i, j) {
return 'translate (-10, 40) rotate(-90 0,0)'
});
// move x-axis label down
xTicks.select('.nv-axislabel').attr("y", 90)
Hope it helps
I have a D3 project where I'm drawing a time axis along the left side of the screen. I want to have it smoothly transition on window resize so I'm using D3 transitions. However the axis setup appears to be changing the "dy" attribute on the tick labels immediately causing the tick labels to jump downward and then transition back into their normal place any time the SVG is transitioned. Is there any way to set the "dy" attribute of the tick text as part of the axis call or a better way to transition?
My initial (one-time) axis setup:
var timeScale = d3.time.scale().domain([minTime, maxTime]);
var yAxis = d3.svg.axis().scale(timeScale).tickFormat(d3.time.format("%-m/%-d %-I:%M%p")).orient("right");
I have a function to update/transition the SVG elements I'm using. The first time the SVG is drawn init is set to true, false afterwards.
function updateSVG(init) {
...
timeScale.rangeRound([topPadding, svgHeight]);
// Use a transition to update the axis if this is an update
var t = (init) ? svgContainer : svgContainer.transition().duration(750);
// {1}: Create Y axis
t.select("g.axis").call(yAxis);
// {2}: Move Y axis labels to the left side
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("dy", -4);
...
}
On an update at {1} tick labels all have a "dy" attribute of "-4" from the previous attr() call. At {2} applying the axis resets the "dy" attribute of these elements to a default of ".32em" after which they transition slowly back to "-4" causing them to jitter up and down as the window is resized and the axis is redrawn.
Here is a working JSFiddle that demonstrates the jump on the y-axis when the Result box is resized, resize just by a few pixels and it should be obvious: http://jsfiddle.net/YkDk4/1/
Just figured this out. By applying a "transform" attribute instead of a "dy" attribute the axis call() does not overwrite the value. So:
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("dy", -4);
becomes:
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("transform", "translate(0,-4)");
and everything transitions smoothly.
According to the bug fix made in response to this problem with the text-anchor attribute:
How to tweak d3 axis attributes when transition is present?
It looks like the dy attribute is supposed to update immediately during transitions...but it's not.
In any case, the easiest solution is simply to take the dy update OUT of the transition and apply it directly:
t.select(".y")
.call(yAxis);
chartSvg.selectAll(".y g.tick > text")
.attr("dy", -4);
That should avoid the "bounce".