I have three array of objects.
I want to create a chart with 3 lines, the Dates are the same for the three arrays. The Y for peakUsage and avgUsage are the same values so they are horizontal straight lines
This code show the Y and X Axises but failing with drawing the actual lines.
data: { x: Date; y: number }[],
peakUsage: { x: Date; y: number }[],
avgUsage: { x: Date; y: number }[]
const axisThickness = 60;
const width = (params.width || 500) - axisThickness;
const height = (params.height || 500) - axisThickness;
const { document } = new JSDOM('').window;
// Create D3 container with SVG element
const div = d3.select(document.body).append('div');
const svg = div
.attr('class', 'container')
.append('svg')
.attr('xmlns', 'http://www.w3.org/2000/svg')
.attr('width', width axisThickness)
.attr('height', height axisThickness);
const yScale = d3.scaleLinear().range([height, 0]);
yScale.domain([0, Math.max(...data.map((d) => d.y))]);
const xScale = d3
.scaleTime()
.range([0, width])
.domain(
d3.extent(data, function (d) {
return new Date(d.x);
}) as Date[]
);
const g = svg.append('g').attr('transform', `translate(${axisThickness},${axisThickness / 2})`);
g.append('g').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale));
g.append('g')
.call(
d3
.axisLeft(yScale)
.tickFormat(function (d) {
return `${d}`; // Label text
})
.ticks(8)
)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '-5.1em')
.attr('text-anchor', 'end')
.attr('fill', 'black')
.text('Est. kWh');
g.selectAll('.line')
.enter()
.append('path')
.data(data)
.attr('fill', 'none')
.attr('stroke', 'green')
.attr('stroke-width', 1.5)
.attr('d', function (d) {
return d3
.line()
.x(function (d: any) {
return xScale(d.x);
})
.y(function (d: any) {
return yScale(d.y);
}) as any;
});
g.selectAll('.line')
.enter()
.append('path')
.data(peakUsage)
.attr('fill', 'none')
.attr('stroke', 'Orange')
.attr('stroke-width', 1.5)
.attr(
'd',
d3
.line()
.x(function (d: any) {
return xScale(d.x);
})
.y(function (d: any) {
return yScale(d.y);
}) as any
);
g.selectAll('.line')
.enter()
.append('path')
.data(avgUsage)
.attr('fill', 'none')
.attr('stroke', 'blue')
.attr('stroke-width', 1.5)
.attr(
'd',
d3
.line()
.x(function (d: any) {
return xScale(d.x);
})
.y(function (d: any) {
return yScale(d.y);
}) as any
);
What I am doing wrong?
CodePudding user response:
This bit is in the wrong order:
g.selectAll('.line')
.enter()
.append('path')
.data(data)
It should be:
g.selectAll('.line')
.data(data)
.enter()
.append('path')
But that does not fix your issue. Since you are using 3 different arrays for each line individually (a better approach is using just one array with 3 inner arrays, but that's another issue...), you can simply declare the line generator...
const lineGenerator = d3.line()
.x(function (d: any) {
return xScale(d.x);
})
.y(function (d: any) {
return yScale(d.y);
})
... and then, for each path, do:
g.append('path')
.attr('fill', 'foo')
.attr('stroke', 'bar')
.attr('stroke-width', 'baz')
.attr('d', lineGenerator(pathDataHere))
//the data for each line -----^