【问题标题】:StackedBar Chart with missing ToolTip in Angular and D3.jsAngular 和 D3.js 中缺少工具提示的堆积条形图
【发布时间】:2021-09-28 18:07:42
【问题描述】:

我已经调整了 this 示例以使用最新的 AngularD3

它工作正常(经过一点修改),但我在悬停时没有得到工具提示等...

<h3>Stacked Bar Chart with Tooltips</h3>

<figure id="stacked-bar-tooltip"></figure>

如果你搜索这个ID,你会看到它是绘制的单点:

import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'app-stacked-bar-tooltip',
  templateUrl: './stacked-bar-tooltip.component.html',
  styleUrls: ['./stacked-bar-tooltip.component.css']
})
export class StackedBarTooltipComponent implements OnInit {

  data = [
    {"group": "Insulin", "Low": "6", "Normal": "2.75", "High": "5.25"},
    {"group": "Vit B12", "Low": "1", "Normal": "3", "High": "1"},
    {"group": "Vit D3", "Low": "1", "Normal": "3", "High": "1"},
    {"group": "Zinc", "Low": "1", "Normal": "3", "High": "1"}
  ];

  svg: any;

  margin = 50;
  width = 750 - (this.margin * 2);
  height = 400 - (this.margin * 2);

  ngOnInit(): void {
    this.createSvg();
    this.drawBars(this.data);
  }

  createSvg(): void {
    this.svg = d3.select("figure#stacked-bar-tooltip")
    .append("svg")
    .attr("width", this.width + (this.margin * 2))
    .attr("height", this.height + (this.margin * 2))
    .append("g")
    .attr("transform", "translate(" + this.margin + "," + this.margin + ")");
  }

  drawBars(data): void {
    
    // List of subgroups; i.e. the header of the csv data:
    // Prepare the array with the keys for stacking.
    const dataColumns = Object.keys(data[0]);
    const subgroups = dataColumns.slice(1)

    // List of groups; i.e. value of the first
    // column - group - shown on the X axis.
    const groups = data.map(d => d.group);

    // Create the X-axis band scale.
    const x = d3.scaleBand()
    .domain(groups)
    .range([0, this.width])
    .padding(0.2);

    // Draw the X-axis on the DOM.
    this.svg.append("g")
    .attr("transform", "translate(0," + this.height + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0));
    
    // Create the Y-axis band scale.
    const y = d3.scaleLinear()
    .domain([0, 14])
    .range([this.height, 0]);

    // Draw the Y-axis on the DOM.
    this.svg.append("g")
    .call(d3.axisLeft(y));

    // color palette = one color per subgroup
    const color = d3.scaleOrdinal()
    .domain(subgroups)
    .range(['#ffffcc','#4daf4a', '#e41a1c']);

    // Stack the data per subgroup.
    const stackedData = d3.stack()
    .keys(subgroups)
    (data);

    // Create a tooltip.
    const tooltip = d3.select("#stacked-bar-tooltip")
    .append("figure")
    .style("opacity", 0)
    .attr("class", "tooltip")
    .style("background-color", "white")
    .style("border", "solid")
    .style("border-width", "1px")
    .style("border-radius", "5px")
    .style("padding", "10px")

    // Mouse function that change the tooltip when the user hovers/moves/leaves a cell.
    const mouseover = function(event, d) {
      /********** Hack! Otherwise, the following line would not work:
      const subgroupName = d3.select(this.parentNode).datum().key; */
      const subgroupNameObj: any = d3.select(this.parentNode).datum();
      const subgroupName = subgroupNameObj.key;
      /************ End of Hack! ************/
      const subgroupValue = d.data[subgroupName];
      tooltip.html("subgroup: " + subgroupName + "<br>" + "Value: " + subgroupValue)
            .style("opacity", 1)        
    }
    const mousemove = function(event, d) {
      tooltip.style("transform", "translateY(-55%)")  
            .style("left", (event.x)/2+"px")
            .style("top", (event.y)/2-30+"px")
    }
    const mouseleave = function(event, d) {
      tooltip.style("opacity", 0)
    }

    // Create and fill the stacked bars.
    this.svg.append("g")
    .selectAll("g")
    .data(stackedData)
    .join("g")
    .attr("fill", d => color(d.key))
    .selectAll("rect")    
    .data(d => d)
    .join("rect")
    .attr("x", d => x(d.data.group))
    .attr("y", d => y(d[1]))
    .attr("height", d => y(d[0]) - y(d[1]))
    .attr("width", x.bandwidth())
    .attr("stroke", "grey")
    .on("mouseover", mouseover)
    .on("mousemove", mousemove)
    .on("mouseleave", mouseleave);
  }
}

我在 SandBox 中创建了这个项目(这里是 link),但奇怪的是,它在那里工作,但在我的 Angular 项目中却没有......

此外,当我检查该图时,我发现工具提示实际上正在工作:

我做错了什么或遗漏了什么,工具提示完全丢失了?

【问题讨论】:

  • 这些可能很难定位,因为图形是 svg,工具提示 div 是 html 元素,很难知道选择和附加到什么。我发现这很有帮助:stackoverflow.com/questions/21153074/… 如果没有 Angular 样板,很难直接排除故障。您可以在此 repro 中看到,它不仅仅是将工具提示附加到主体,bc 这将使其难以定位。 codesandbox.io/s/spring-pond-b8m7k?file=/index.html你能在 Codesandbox 中做一个最小的 Angular 复制吗?
  • @MGO 感谢您的回复。我为它创建了一个沙箱。奇怪,它实际上应该在那里工作,但不在我的项目中......这是link

标签: javascript angular typescript d3.js


【解决方案1】:

事实证明它一直都在工作,虽然由于其他应用程序组件的原因,位置偏远,所以它会显示在我无法看到的页面顶部。

我修改了页面 x 和 y 值如下使其显示在鼠标指针上方:

const mousemove = function (event, d) {
      tooltip.style("transform", "translateY(-55%)")
        .style("left", (event.x - 50) + "px")
        .style("top", (event.y + 450) + "px");
}

我关于定位的问题仍然存在:无论如何我如何让这部分显示在鼠标指针上方通过修改现有代码

【讨论】:

    猜你喜欢
    • 2013-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多