gpt4 book ai didi

javascript - 如何让 d3 树形图单元格文本换行而不溢出其他单元格

转载 作者:行者123 更新时间:2023-12-02 23:28:28 25 4
gpt4 key购买 nike

我的 d3 TreeMap 中单元格的文本不会包裹并溢出其他单元格。这是我的project

我希望文本看起来像这样 project 。我已经查看了他们的代码(以及许多其他代码),但我无法让它在我的项目中运行。

问题区域是:

svg.append('text')
.selectAll('tspan')
.data(root.leaves())
.enter()
.append('tspan')
.attr("x", (d) => d.x0 + 5)
.attr("y", (d) => d.y0 + 20)
.text( (d) => d.data.name) //.html( (d) => d.data.name.replace(/\s/g, "<br>"))
.attr("font-size", "0.6em")
.attr("fill", "white");

我尝试使用 .html 而不是评论中的 .text 。在 Safari 和 Chrome 中,文本仍然溢出单元格。在 Firefox 中,仅显示电影名称的第一个单词。

最佳答案

我们有两个选项可以以与您提供的示例类似的方式显示文本。

第一个也是最简单的方法是保留代码结构并执行类似的过程来分割文本,如所提供的示例:

d.data.name.split(/(?=[A-Z][^A-Z])/g)

所以让我们稍微改变一下你的代码:

  svg.selectAll('text')
.data(root.leaves())
.enter()
.append('text')
.selectAll('tspan')
.data(d => {
return d.data.name.split(/(?=[A-Z][^A-Z])/g) // split the name of movie
.map(v => {
return {
text: v,
x0: d.x0, // keep x0 reference
y0: d.y0 // keep y0 reference
}
});
})
.enter()
.append('tspan')
.attr("x", (d) => d.x0 + 5)
.attr("y", (d, i) => d.y0 + 15 + (i * 10)) // offset by index
.text((d) => d.text)
.attr("font-size", "0.6em")
.attr("fill", "white");

这应该可以实现所需的显示。我们必须考虑到标签很难以避免重叠的方式定位和显示,因为它在构建时需要更多的计算。

第二种方法是稍微更改代码结构并创建单元格,与提供的示例非常相似:

const cell = svg.selectAll('g')
.data(root.leaves())
.enter()
.append('g') // create a group for each cell / movie
.attr('transform', d => `translate(${d.x0},${d.y0})`) // let the group element handle the general positioning
.on('mousemove', d => {
//...
})
.on('mouseout', d => {
//...
});

cell.append('rect') // append rect for each cell / movie
.attr('id', d => d.data.id)
.attr('class', 'tile')
.attr('data-name', d => d.data.name)
.attr('data-value', d => d.data.value)
.attr('data-category', d => d.data.category)
.attr('width', d => d.x1 - d.x0)
.attr('height', d => d.y1 - d.y0)
.attr('fill', d => color(d.data.category));

cell.append('text') // append text node for each cell / movie
.selectAll('tspan')
.data(d => d.data.name.split(/(?=[A-Z][^A-Z])/g)) // split the name and use that as data to create indiviual tspan elements
.enter()
.append('tspan') // append tspan node for each element of the string which got split
.attr('font-size', '8px')
.attr('x', 4)
.attr('y', (d, i) => 13 + 10 * i) // offset the y positioning with the index of the data
.text(d => d);

CodePen for approach 1

CodePen for approach 2

方法 1 的完整代码:

// !! IMPORTANT README:

// You may add additional external JS and CSS as needed to complete the project, however the current external resource MUST remain in place for the tests to work. BABEL must also be left in place.

const w = 960;
const h = 600;
const padding = 60;
const svg = d3.select("#container").append("svg")
.attr("width", w).attr("height", h);
const legendsvg = d3.select("#legend").append("svg")
.attr("width", 960).attr("height", 50);
const legendPadding = 10;

d3.json("https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/movie-data.json")
.then(function(data) {
var root = d3.hierarchy(data).sum(function(d){ return d.value});

var treeMap = d3.treemap()
.size([w, h])
.paddingInner(1);

treeMap(root);

const toolTip = d3
.select("#container")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);

var color = d3.scaleOrdinal()
.domain(["Action", "Drama", "Adventure", "Family", "Animation", "Comedy", "Biography"])
.range(["#db8a00", "#75b0ff", "#13ad37", "#5d6d00", "#757582", "#d37cff", "#f96868"])

svg.selectAll("rect")
.data(root.leaves())
.enter().append("rect")
.attr("class", "tile")
.attr("data-name", (d) => d.data.name)
.attr("data-category", (d) => d.data.category)
.attr("data-value", (d) => d.data.value)
.attr('x', (d) => d.x0)
.attr('y', (d) => d.y0)
.attr('width', (d) => d.x1 - d.x0)
.attr('height', (d) => d.y1 - d.y0)
.style("stroke", "black")
.style("fill", (d) => color(d.parent.data.name))
.on("mouseover", (d, i) => {
toolTip
.transition()
.duration(0)
.style("opacity", 0.8);
toolTip
.attr("id", "tooltip")
.html(function() {
return "<span>" + "Name: " + d.data.name + "<br />" + "Category: " + d.data.category + "<br />" + "Value: " + d.data.value + "</span>";
})
.style("left", d3.event.pageX - 87.5 + "px") // -87.5 is half width of tooltip in css
.style("top", d3.event.pageY - 75 + "px")
.attr("data-value", d.data.value);
})
.on("mouseout", function(d) {
toolTip
.transition()
.duration(0)
.style("opacity", 0);
});

svg.selectAll('text')
.data(root.leaves())
.enter()
.append('text')
.selectAll('tspan')
.data(d => {
return d.data.name.split(/(?=[A-Z][^A-Z])/g) // split the name of movie
.map(v => {
return {
text: v,
x0: d.x0, // keep x0 reference
y0: d.y0 // keep y0 reference
}
});
})
.enter()
.append('tspan')
.attr("x", (d) => d.x0 + 5)
.attr("y", (d, i) => d.y0 + 15 + (i * 10)) // offset by index
.text((d) => d.text)
.attr("font-size", "0.6em")
.attr("fill", "white");

console.log(root.leaves());
/*svg.selectAll("text")
.data(root.leaves())
.enter()
.append("text")
.attr("x", function(d){ return d.x0+5})
.attr("y", function(d){ return d.y0+20})
.text(function(d){ return d.data.name })
.attr("font-size", "0.6em")
.attr("fill", "white")*/

legendsvg.selectAll('rect')
.data(root.children)
.enter()
.append('rect')
.attr('class', 'legend-item')
.style('stroke', 'white')
.attr('x', (d,i) => i*140 )
.attr('width', 130)
.attr('height', 20)
.style('fill', d => color(d.data.name))

legendsvg.selectAll('text')
.data(root.children)
.enter()
.append('text')
.attr('x', (d,i) => i*140)
.attr('y', 40)
.text(d => d.data.name);

//had to change the legend below because it wouldn't pass fcc test
/*legendsvg.append("g").classed("legend", true).classed("legend-item", true);
const legend = d3.legendColor().shape("rect")
.shapeWidth(90).cells(7).orient("horizontal").scale(color);
legendsvg.select(".legend").call(legend);*/
});

方法 2 的完整代码:

// !! IMPORTANT README:

// You may add additional external JS and CSS as needed to complete the project, however the current external resource MUST remain in place for the tests to work. BABEL must also be left in place.

const w = 960;
const h = 600;
const padding = 60;
const svg = d3.select("#container").append("svg")
.attr("width", w).attr("height", h);
const legendsvg = d3.select("#legend").append("svg")
.attr("width", 960).attr("height", 50);
const legendPadding = 10;

d3.json("https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/movie-data.json")
.then(function(data) {
var root = d3.hierarchy(data).sum(function(d){ return d.value});

var treeMap = d3.treemap()
.size([w, h])
.paddingInner(1);

treeMap(root);

const toolTip = d3
.select("#container")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);

var color = d3.scaleOrdinal()
.domain(["Action", "Drama", "Adventure", "Family", "Animation", "Comedy", "Biography"])
.range(["#db8a00", "#75b0ff", "#13ad37", "#5d6d00", "#757582", "#d37cff", "#f96868"])

const cell = svg.selectAll('g')
.data(root.leaves())
.enter()
.append('g')
.attr('transform', d => `translate(${d.x0},${d.y0})`)
.on('mousemove', d => {
toolTip.transition()
.duration(200)
.style('opacity', 0.75);
toolTip.attr('data-value', d.data.value);
toolTip.html(
'Name: ' + d.data.name + '<br>' +
'Category: ' + d.data.category + '<br>' +
'Value: ' + d.data.value
)
.style('top', `${d3.event.pageY + 10}px`)
.style('left', `${d3.event.pageX + 8}px`);
})
.on('mouseout', d => {
toolTip.transition()
.duration(200)
.style('opacity', 0);
});


cell.append('rect')
.attr('id', d => d.data.id)
.attr('class', 'tile')
.attr('data-name', d => d.data.name)
.attr('data-value', d => d.data.value)
.attr('data-category', d => d.data.category)
.attr('width', d => d.x1 - d.x0)
.attr('height', d => d.y1 - d.y0)
.attr('fill', d => color(d.data.category));

cell.append('text')
.selectAll('tspan')
.data(d => d.data.name.split(/(?=[A-Z][^A-Z])/g))
.enter()
.append('tspan')
.attr('font-size', '8px')
.attr('x', 4)
.attr('y', (d, i) => 13 + 10*i)
.text(d => d);



legendsvg.selectAll('rect')
.data(root.children)
.enter()
.append('rect')
.attr('class', 'legend-item')
.style('stroke', 'white')
.attr('x', (d,i) => i*140 )
.attr('width', 130)
.attr('height', 20)
.style('fill', d => color(d.data.name))

legendsvg.selectAll('text')
.data(root.children)
.enter()
.append('text')
.attr('x', (d,i) => i*140)
.attr('y', 40)
.text(d => d.data.name);

//had to change the legend below because it wouldn't pass fcc test
/*legendsvg.append("g").classed("legend", true).classed("legend-item", true);
const legend = d3.legendColor().shape("rect")
.shapeWidth(90).cells(7).orient("horizontal").scale(color);
legendsvg.select(".legend").call(legend);*/
});

关于javascript - 如何让 d3 树形图单元格文本换行而不溢出其他单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56623476/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com