Javascript 如何确保树映射单元格中的文本不会溢出?

Javascript 如何确保树映射单元格中的文本不会溢出?,javascript,d3.js,treemap,Javascript,D3.js,Treemap,类似的东西。但是我有很多数据,所以文本很多。那么,确保每个单独的文本在树状图单元格中完美包裹的最佳方法是什么 我使用下划线.nest来嵌套JSON数据,所以看起来像这样 {"children":[{"name":"Afghanistan", "children":[{"name":"Qal eh-ye Now","value":2997}, {"name":"Mahmud-E Eraqi","value":7407} 但是当我画树形图的时候,文字到处都是, 这是我添加文本的D3代码:

类似的东西。但是我有很多数据,所以文本很多。那么,确保每个单独的文本在树状图单元格中完美包裹的最佳方法是什么

我使用下划线.nest来嵌套JSON数据,所以看起来像这样

{"children":[{"name":"Afghanistan",
 "children":[{"name":"Qal eh-ye Now","value":2997},
 {"name":"Mahmud-E Eraqi","value":7407}
但是当我画树形图的时候,文字到处都是,

这是我添加文本的D3代码:

 cells
.append("text")
.attr("x", function (d) {
  return d.x + d.dx / 2;
})
.attr("y", function (d) {
  return d.y + d.dy / 2;
})
.attr("text-anchor", "middle")
.text(function (d) { return d.children ? null : d.name })
完整数据集:

我的完整代码

 var coordinates = { x: 0, y: 0 };
 var margin = { top: 40, right: 10, bottom: 90, left: 20 }
  var cfg = {
    margin: { top: 40, right: 10, bottom: 90, left: 140 },
    width: 960 - margin.left - margin.right,
    height: 500 - margin.top - margin.bottom,
    color: d3.scale.category20()
  };

  //Put all of the options into a variable called cfg
  if ('undefined' !== typeof options) {
    for (var i in options) {
      if ('undefined' !== typeof options[i]) { cfg[i] = options[i]; }
    }//for i
  }

  var treemap,
    legendCategories,
    uniqueCategories;
  var half = cfg.height / 2;
  var tool = d3.select("body").append("div").attr("class", "toolTip");

  /////////////////////////////////////////////////////////
  //////////// Create the container SVG and g /////////////
  /////////////////////////////////////////////////////////


  //Remove whatever chart with the same id/class was present before
  d3.select(id).select("svg").remove();

  //Initiate the radar chart SVG
  var canvas = d3
    .select(id)
    .append("svg")
    .attr("class", "chart")
    .attr("width", cfg.width + cfg.margin.left + cfg.margin.right)
    .attr("height", cfg.height + cfg.margin.top + cfg.margin.bottom)
    .attr("id", "canvas");
  var innercanvas = canvas
    .append("g")
    .attr("class", "innercanvas")
    .attr("transform", "translate(" + cfg.margin.left + "," + cfg.margin.top + ")");

  legendCategories = data.children.map(a => a.name);
  uniqueCategories = legendCategories.filter(onlyUnique);

  var categoryTitle = String(categoryKey);
  categoryTitle = categoryTitle.substring(categoryTitle.indexOf("." + 1));
  categoryScale = cfg.color;
  categoryScale.domain(uniqueCategories);
  verticalLegend = d3.svg
    .legend()
    .labelFormat("none")
    .cellPadding(5)
    .orientation("vertical")
    .units(categoryTitle)
    .cellWidth(20)
    .cellHeight(10)
    .place(coordinates)
    .inputScale(categoryScale)
    .cellStepping(10);


  treemap = d3.layout
    .treemap()
    .round(false)
    .size([cfg.width, cfg.height])
    .padding(.25)
    .sticky(true)
    .nodes(data);

  var cells = innercanvas
    .selectAll(".newcell")
    .data(treemap)
    .enter()
    .append("g")
    .attr("class", "newcell");

  cells
    .append("rect")
    .attr("x", function (d) {
      return d.x;
    })
    .attr("y", function (d) {
      return d.y;
    })
    .attr("id", "rectangle")
    .attr("width", function (d) {
      return d.dx;
    })
    .attr("height", function (d) {
      return d.dy;
    })
    .style("fill", function (d) {
      return d.children ? cfg.color(d.name) : null;
    })
    .attr("stroke", "#000000")
    .attr('pointer-events', 'all')
    .on("mousemove", function (d) {
      tool.style("left", d3.event.pageX + 10 + "px")
      tool.style("top", d3.event.pageY - 20 + "px")
      tool.style("display", "inline-block");
      tool.html(d.children ? null : d.name + "<br>" + d.value);
    }).on("mouseout", function (d) {
      tool.style("display", "none");
    });

  cells
    .append("text")
    .attr("x", function (d) {
      return d.x + d.dx / 2;
    })
    .attr("y", function (d) {
      return d.y + d.dy / 2;
    })
    .attr("text-anchor", "middle")
    .text(function (d) { return d.children ? null : d.name })



  canvas
    .append("g")
    .attr("transform", "translate(40,50)")
    .attr("class", "legend")
    .attr("id", "legend")
    .call(verticalLegend);




  function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
  }
var坐标={x:0,y:0};
var margin={顶部:40,右侧:10,底部:90,左侧:20}
var cfg={
边距:{顶部:40,右侧:10,底部:90,左侧:140},
宽度:960-边距。左侧-边距。右侧,
高度:500-边距。顶部-边距。底部,
颜色:d3.scale.category20()
};
//将所有选项放入名为cfg的变量中
如果('undefined'!==选项类型){
对于(选项中的var i){
if('undefined'!==typeof options[i]){cfg[i]=options[i];}
}//因为我
}
var treemap,
传奇类,
唯一类别;
var half=cfg.height/2;
变量工具=d3。选择(“主体”)。追加(“div”)。属性(“类”,“工具提示”);
/////////////////////////////////////////////////////////
////////////创建容器SVG和g/////////////
/////////////////////////////////////////////////////////
//删除以前存在的具有相同id/类的任何图表
d3.select(id).select(“svg”).remove();
//启动雷达图SVG
var=d3
.选择(id)
.append(“svg”)
.attr(“类别”、“图表”)
.attr(“宽度”,cfg.width+cfg.margin.left+cfg.margin.right)
.attr(“高度”,cfg.height+cfg.margin.top+cfg.margin.bottom)
.attr(“id”、“画布”);
var innercanvas=canvas
.附加(“g”)
.attr(“类”、“内部画布”)
.attr(“转换”、“转换”(+cfg.margin.left+)、“+cfg.margin.top+”);
legendCategories=data.children.map(a=>a.name);
uniqueCategories=legendCategories.filter(仅限Yunique);
var categorytle=字符串(categoryKey);
categoryTitle=categoryTitle.substring(categoryTitle.indexOf(“.”+1));
categoryScale=cfg.color;
领域(唯一类别);
verticalLegend=d3.svg
.图例()
.labelFormat(“无”)
.1(5)
.方向(“垂直”)
.单位(类别)
.单元宽度(20)
.牢房高度(10)
.地点(坐标)
.输入比例(类别比例)
.1(10);
treemap=d3.0布局
.treemap()
.round(假)
.size([cfg.width,cfg.height])
.padding(.25)
.粘性(真)
.节点(数据);
var cells=innercanvas
.selectAll(“.newcell”)
.数据(树形图)
.输入()
.附加(“g”)
.attr(“类别”、“新单元”);
细胞
.append(“rect”)
.attr(“x”,函数(d){
返回d.x;
})
.attr(“y”,函数(d){
返回d.y;
})
.attr(“id”、“矩形”)
.attr(“宽度”,函数(d){
返回d.dx;
})
.attr(“高度”,功能(d){
返回d.dy;
})
.样式(“填充”,功能(d){
返回d.children?cfg.color(d.name):空;
})
.attr(“笔划”,“000000”)
.attr('pointer-events','all')
.on(“mousemove”,函数(d){
工具样式(“左”,d3.event.pageX+10+“px”)
工具样式(“顶部”,d3.event.pageY-20+“px”)
工具样式(“显示”、“内联块”);
html(d.children?null:d.name+“
”+d.value); }).开启(“鼠标出”,功能(d){ 工具样式(“显示”、“无”); }); 细胞 .append(“文本”) .attr(“x”,函数(d){ 返回d.x+d.dx/2; }) .attr(“y”,函数(d){ 返回d.y+d.dy/2; }) .attr(“文本锚定”、“中间”) .text(函数(d){返回d.children?null:d.name}) 帆布 .附加(“g”) .attr(“转换”、“翻译(40,50)”) .attr(“类”、“图例”) .attr(“id”、“图例”) .呼叫(垂直呼叫); 函数onlyUnique(值、索引、自身){ 返回self.indexOf(value)==索引; }
有几种方法可以解决这样一个问题,即拥有一个由不同长度字符串组成的大型数据集,我们需要将这些字符串放入不同大小的框中

一种方法是为每个矩形元素添加一个剪切路径(
clipppath
),但我认为这对于这样的可视化来说太过分了,所以我们将使用其他方法

首先,您可以为每个
g
添加一个title元素;大多数浏览器的默认操作是在鼠标悬停在标题上时显示工具提示。因此:

cells
  .append('title')
  .text(function(d){ return d.name });
现在让我们看看文本元素。为样式表或文档头中的文本节点设置
字体系列
字体大小
,以便处理可预测的文本大小

.newcell text {
  font-family: Arial, sans-serif;
  font-size: 10px;
}
我建议将文本稍微向下移动,因为当前代码将文本基线设置在单元格的垂直中心,这太高了。这里我添加了一个偏移量
0.35em

selection
  .append("text")
  .attr("x", function (d) {
    return d.x + d.dx / 2;
  })
  .attr("y", function (d) {
    return d.y + d.dy / 2;
  })
  .attr('dy', '.35em')
  .attr("text-anchor", "middle")
  .text(function (d) {
    return d.children ? '' : d.name;
  })
我们可以通过改变不透明度来过滤文本节点的可见性(这意味着我们可以轻松切换不透明度来显示/隐藏文本),使用

我们可以使用各种不同的方法来决定是显示还是隐藏文本。一种是单元格必须具有最小宽度和最小高度才能显示其中的文本,例如

  var minHeight = 12,
  minWidth = 20;
  cells
    .style('opacity', function(d){
      if ( d.dx <= minWidth || d.dy <= minHeight ) {
        return 0
      };
      return 1;
    });
还有一种方法是将文本元素的边框大小与单元格的高度和宽度进行比较:

  cells
    .style('opacity', function(d){
      var bbox = this.getBBox();
      if ( d.dx <= bbox.width || d.dy <= bbox.height ) {
        return 0;
      }
      return 1;
    });
单元格
.style('opacity',function(d){
var bbox=this.getBBox();

如果(d.dx这里有很多问题——主要的一个问题是你有大量的文本数据,其中很多数据必须放在很小的单元格中。根据你使用的d3的版本,你可能有错误的代码来计算
x
y
属性。你能编辑你的问题以提供一个最小的comp吗删除此问题的示例?使用完整数据集链接到.block也会很有帮助。@ialarmedalien I'm u
  var pt_px = 0.75, // convert font size in pt into pixels
  font_size = 10,   // or whatever it is set to in the stylesheet
  averageLetterWidth = 0.58344; // average character width for Arial

  cells
    .style('opacity', function(d){
      if ( d.name.length * averageLetterWidth * pt_px * font_size >= d.dx ) {
        return 0
      }
      return 1;
    });
  cells
    .style('opacity', function(d){
      var bbox = this.getBBox();
      if ( d.dx <= bbox.width || d.dy <= bbox.height ) {
        return 0;
      }
      return 1;
    });
  var h_pad = 2, // 2 pixels vertical padding
  v_pad = 4; // 4 pixels of horizontal padding (2 px at each side)
  cells
    .style('opacity', function(d){
      var bbox = this.getBBox();
      if ( d.dx <= bbox.width + h_pad || d.dy <= bbox.height + v_pad ) {
        return 0;
      }
      return 1;
    });