Hello I am trying to create an area chart with d3 and am trying to match d3's generated coordinates with a d3.symbolCircle.
This is what I have:
https://codepen.io/anon/pen/bozoQa
You will notice that in the current state the dots do not match the generated lines.
The reason for that is because of line 133.
const area = d3.area()
.x((d, i) => xScale(data.xAxis.categories[i]))
.y0(viewModel.height)
.y1((d) => yScale(d))
.curve(d3.curveBasis)
This creates the area as curved instead of a straight line. If I remove that the dots would match and it would work but I need this chart to have curved lines.
Taking this into consideration how can I set the dots in the correct position no matter what type of curve I will be setting on the area chart?
You should use another interpolation function, for example, curveCardinal. Look at this demo page, when you can choose interpolation function for your case (click on names of functions appears/disappears the corresponding line).
Look at my fork of your pen with curveCardinal - https://codepen.io/levvsha/pen/YrBEzN?editors=1010
const area = d3.area()
.x((d, i) => xScale(data.xAxis.categories[i]))
.y0(viewModel.height)
.y1((d) => yScale(d))
.curve(d3.curveCardinal);
Related
Running D3 v6.
This is a multi part question as in trying to solve the original problem I have a question about D3 and mouseevents. A quick note while using my fiddle, if you press the ESC key it will clear the draw line behavior.
How to draw a line from one node to another, following the cursor, regardless of zoom level and pan position?
Why does the line I draw behave differently when the .on('mousemove') is applied to an svg versus a g element?
Problem 1. The problem I am facing is that when panning and zooming, the end point of the line does not follow the cursor properly because the container I'm zooming on had it's x and y translated. Zoom in and click on a node to see the issue.
Related fiddle
This works just fine in my demo, until zooming and panning are involved. I've managed to take care of the panning issues by using d3.zoomTransform() to get the current [x,y] and apply that to the end point of the line. I cannot figure out to accommodate the zoom level though. I have tried transform(scale(zoomLevel.k)) but this doesn't work great. To recreate this issue, click a node without panning/zooming and observe the line follows the cursor. Zoom the graph and then click a node and observe the line does not follow the cursor.
Problem 2. I thought that I could solve the above issue by having the cursor react to mouse events on the g element I use for zooming and positioning rather than my parent svg element. When the mousemove event is on the g the line follows the cursor regardless of zoom/pan but is very laggy and I don't understand why.
SVG mouseevent
G mouseevent
Brief code overview, view fiddles for full code
let sourceNode;
const svg = d3.select("#chart")
.attr("viewBox", [0, 0, width, height]);
const g = svg.append('g');
const drawLine = g.append('line').attr('stroke', 'red').attr('stroke-width', 5).attr('visibility', 'hidden')
const nodes = g.append(//do node stuff)
const links = g.append(//do link stuff)
svg.call(d3.zoom().on('zoom', (event) => {
g.attr('transform', `translate(${event.transform.x}, ${event.transform.y}) scale(${event.transform.k})`)
}))
node.on('click', (event, d) => {
sourceNode = d
})
svg.on('mousemove', (event) => {
if (sourceNode) {
const currentZoom = d3.zoomTransform(svg.node());
drawLine
.attr('visibility', 'visible')
.attr('x1', sourceNode.x)
.attr('y1', sourceNode.y)
// Remove the currentZoom offset and observe the line being jank
.attr('x2', d3.pointer(event)[0] - currentZoom.x)
.attr('y2', d3.pointer(event)[1] - currentZoom.y);
}
})
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'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
I was extending Sunburst chart of D3. Whenever user clicks on a specific legend then it will highlight all the path associated with that label if that legend is last in the sequence.
Here is working fiddle - http://output.jsbin.com/pezehoveso
I think my problem is in below function -
function updatePaths(selectedPath) {
var resultedPath = getSelectedPaths(selectedPath);
// Fade all the segments.
// Then highlight only those that are an ancestor of the current segment.
vis.selectAll("path")
.filter(function(d, i) {
return (resultedPath);
})
.style("opacity", 1);
}
Somehow I'm unable to get selected path highlighted. It's highlighting all the paths. What am I missing?
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()