Reputation: 47
I have d3 line graph that is constantly updated with new set of data. The issue is my line graph is drawn above the some rectangular blocks. On page load my line graph is always in the front of the rect but after the page is being refreshed the line graph is going behind the rectangular block. Can any of you help me fix this problem ?
My code is set up like this
function drawRect(SVG, cData, type) {
let selector = '.ca';
let className = 'c a';
let tcHeight = verticalSize + MIN_CELL_PADDING;
let getTranslateString = function (index) {
let yVal = columnHeight - ((index + 1) * tcHeight);
return `translate(${xVal}, ${yVal})`;
let rects = d3.select(columnSVG)
.selectAll(selector)
.data(cData.filter((d) => {
return d;
}));
rects.enter()
.append('g')
.attr('class', className)
.attr('transform', (d, ix) => {
return getTranslateString(ix);
})
.each(function () {
d3.select(this)
.append('rect')
.attr('width', cellSize)
.attr('height', verticalSize)
.attr('rx', 4)
.attr('ry', 4)
.attr('time', (d) => {
return cData.date;
})
.attr('fill', (d) => {
return changeColor(d);
});
});
rects.transition()
.attr('transform', (d, ix) => {
return getTranslateString(ix);
});
rects.each(function (d) {
let node = d3.select(this);
node.selectAll('rects').transition()
.attr('width', cellSize)
.attr('height', verticalSize)
.attr('rx', 4)
.attr('ry', 4)
}
function drawOline(aData, dData, time) {
let aLine = d3.svg.line()
.defined((d) => {
return !isNaN(d.Ptile);
})
.x((d) => {
return ptime(moment(d.day).utc());
})
.y((d) => {
return aY(d.Ptile);
});
let dLine = d3.svg.line()
.defined((d) => {
return !isNaN(d.Ptile);
})
.x((d) => {
return ptime(moment(d.day).utc());
})
.y((d) => {
return dY(d.Ptile);
});
if (aData && aData.length > 0) {
if (g.select('.aline')[0][0] == null) {
g.append('g')
.append('path')
.datum(aData)
.attr('class', 'line aline')
.attr('fill-opacity', 1.0)
.attr('d', aline);
} else {
g.select('.aline')
.datum(aData)
.transition()
.attr('fill-opacity', 1.0)
.attr('d', aline);
}
} else {
g.select('.aline')
.transition()
.attr('fill-opacity', 1.0)
.attr('d', aline);
}
if (dData && dData.length > 0) {
if (g.select('.dline')[0][0] == null) {
g.append('g')
.append('path')
.datum(dData)
.attr('class', 'line dline')
.attr('fill-opacity', 1.0)
.attr('d', dline);
} else {
g.select('.dline')
.datum(dData)
.transition()
.attr('fill-opacity', 1.0)
.attr('d', dline);
}
} else {
g.select('.dline')
.transition()
.attr('fill-opacity', 1.0)
.attr('d', dline);
}
}
Upvotes: 0
Views: 157
Reputation: 22443
The visual occlusion (hiding) of some SVG objects by others (e.g. lines by rects, or vice versa) is very dependent on their drawing order. Unlike HTML/CSS, SVG does not have a true z-index
or "what's on top?" indicator.
The trick is often to draw the items you want to see on top last. That's not always convenient, however. For example, you may not way to redraw lines every time you redraw the blocks.
A way to preserve the visual ordering of objects, even when they're redrawn, is to put them into <g>
groups. The ordering of the groups need not change, even if the items are updated. For example:
var rectsG = svg.append('g').attr('class', 'rects');
var linesG = svg.append('g').attr('class', 'lines');
Then instead of drawing into the global svg
element, direct your appends to individual groups. They will act as layers:
linesG.append('line')
...more here...
rectsG.append('rect')
...more here...
Because the groups are ordered in the document top to bottom, it really doesn't matter what order you draw or redraw their constituent elements. The ordering of the <g>
containers is what will determine visual occlusion.
Upvotes: 2