Reputation: 99
Update method : Thanks in advance. I am creating rectangles based on the api response data. The rectangles will will be removed and re-created when the new data come back from api. I want to achieve same thing for adding text inside the rectangles, means as soon as I receive the fresh data text should be overrided or re-created based on the data.
/* update selection*/
var rectangles = vis.ganttSvgRef.selectAll("rect").data(chartData);
/*exit selection*/
rectangles.exit().remove();
/*enter selection*/
var innerRects = rectangles.enter().append("rect").merge(rectangles)
.attr("x", function (d) {
return vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot);
}
}
})
.attr("width", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
})
.attr("height", barHeight)
.attr("stroke", "none")
.attr("fill", function (d) {
for (var i = 0; i < vesselsNames.length; i++) {
return serviceColorSelector[d.serviceName_data]
}
})
how to add the text in the rectangles in middle, which should also get update based on the data receive. Thanks
Updated code as suggested by @Michael Rovinsky : This code works perfectly fine for appending the text inside the rect, but on few rect the text is overflowing outside the rect area. I don't want to show the text if it overflow from rect area or how can i hide the text if it overflow from rect area ?
var rectangles = vis.ganttSvgRef.selectAll("rect")
.data(chartData);
rectangles.exit().remove();
var innerRects = rectangles.enter().append("g");
let rectinst = innerRects.append("rect").merge(rectangles)
.attr("x", function (d) {
return vis.timeScale(parseTime(d.arrivalTime_data)) +
sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot);
}
}
})
.attr("width", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
})
.attr("height", barHeight)
.attr("stroke", "none")
.attr("fill", function (d) {
for (var i = 0; i < vesselsNames.length; i++) {
return serviceColorSelector[d.serviceName_data]
}
})
let text = vis.ganttSvgRef.selectAll(".rect-text")
.data(chartData);
text.exit().remove();
innerRects.append("text").merge(text)
.attr("class", 'rect-text')
.text(function (d) {
let rectWidth = (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data)));
console.log("rect width : ", rectWidth)
console.log("d.vesselName_data : ",
vis.timeScale(d.vesselName_data.length))
return d.vesselName_data;
})
.attr("x", function (d) {
return (vis.timeScale(parseTime(d.departureTime_data)) -
vis.timeScale(parseTime(d.arrivalTime_data))) / 2 +
vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
})
.attr("y", function (d, i) {
for (var j = 0; j < slotNumber.length; j++) {
if (d.slot == slotNumber[j]) {
return vis.yScale(d.slot) + (barHeight / 2);
}
}
})
.attr("font-size", barHeight / 2)
.attr("text-anchor", "middle")
.attr("text-height", barHeight)
.attr("fill", '#fff');
Upvotes: 0
Views: 931
Reputation: 161
You can write your own text wrapping function d3 based on the rect dimensions and given padding. Please check following link for customised text wrapping and overflow control in d3.js-
Code- text-wrapping-in-d3
function wrap(text) {
text.each(function() {
var text = d3.select(this);
var words = text.text().split(/\s+/).reverse();
var lineHeight = 20;
var width = parseFloat(text.attr('width'));
var y = parseFloat(text.attr('y'));
var x = text.attr('x');
var anchor = text.attr('text-anchor');
var tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('text-anchor', anchor);
var lineNumber = 0;
var line = [];
var word = words.pop();
while (word) {
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > width) {
lineNumber += 1;
line.pop();
tspan.text(line.join(' '));
line = [word];
tspan = text.append('tspan').attr('x', x).attr('y', y + lineNumber * lineHeight).attr('anchor', anchor).text(word);
}
word = words.pop();
}
});
}
function dotme(text) {
text.each(function() {
var text = d3.select(this);
var words = text.text().split(/\s+/);
var ellipsis = text.text('').append('tspan').attr('class', 'elip').text('...');
var width = parseFloat(text.attr('width')) - ellipsis.node().getComputedTextLength();
var numWords = words.length;
var tspan = text.insert('tspan', ':first-child').text(words.join(' '));
// Try the whole line
// While it's too long, and we have words left, keep removing words
while (tspan.node().getComputedTextLength() > width && words.length) {
words.pop();
tspan.text(words.join(' '));
}
if (words.length === numWords) {
ellipsis.remove();
}
});
}
d3.selectAll('.wrapme').call(wrap);
d3.selectAll('.dotme').call(dotme);
Upvotes: 1
Reputation: 7210
Append "g" instead of "rect" on enter():
const containers = rectangles.enter().append("g");
Append "rect" and "text" under "g":
containers.append("rect").attr('width', ...).attr('height', ...)...
containers.append("text").text('My Text Here')...
Upvotes: 1