Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/451.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 向reactjs中的气泡添加工具提示_Javascript_Reactjs_React Native_D3.js_Tooltip - Fatal编程技术网

Javascript 向reactjs中的气泡添加工具提示

Javascript 向reactjs中的气泡添加工具提示,javascript,reactjs,react-native,d3.js,tooltip,Javascript,Reactjs,React Native,D3.js,Tooltip,我有以下d3代码: import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import * as d3 from 'd3'; import tip from 'd3'; export default class BubbleChart extends Component { constructor(props){

我有以下d3代码:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import tip from 'd3';

export default class BubbleChart extends Component {
  constructor(props){
    super(props);

    this.renderChart = this.renderChart.bind(this);
    this.renderBubbles = this.renderBubbles.bind(this);
    this.renderLegend = this.renderLegend.bind(this);
  }
  
  componentDidMount() {
    this.svg = ReactDOM.findDOMNode(this);
    this.renderChart();
  }

  componentDidUpdate() {
    const {
      width,
      height,
    } = this.props;
    if(width !== 0 && height !== 0) {
      this.renderChart();
    }
  }

  render() {
    const {
      width,
      height,
    } = this.props;
    return (
      <svg width={width} height={height} />
    )
  }

  renderChart() {
    const {
      overflow,
      graph,
      data,
      height,
      width,
      padding,
      showLegend,
      legendPercentage,
    } = this.props;
    // Reset the svg element to a empty state.
    this.svg.innerHTML = '';
    // Allow bubbles overflowing its SVG container in visual aspect if props(overflow) is true.
    if(overflow)
      this.svg.style.overflow = "visible";

    const bubblesWidth = showLegend ? width * (1 - (legendPercentage / 100)) : width;
    const legendWidth = width - bubblesWidth;
    const color = d3.scaleOrdinal(d3.schemeCategory20c);

    const pack = d3.pack()
        .size([bubblesWidth * graph.zoom, bubblesWidth * graph.zoom])
        .padding(padding);

    // Process the data to have a hierarchy structure;
    const root = d3.hierarchy({children: data})
    .sum(function(d) { return d.value; })
    .sort(function(a, b) { return b.value - a.value; })
    .each((d) => {
      if(d.data.label) {
        d.label = d.data.label;
        d.id = d.data.label.toLowerCase().replace(/ |\//g, "-");
      }
    });

    // Pass the data to the pack layout to calculate the distribution.
    const nodes = pack(root).leaves();

    // Call to the function that draw the bubbles.
    this.renderBubbles(bubblesWidth, nodes, color);
    // Call to the function that draw the legend.
    if (showLegend) {
      this.renderLegend(legendWidth, height, bubblesWidth, nodes, color);
    }
  }
  

  renderBubbles(width, nodes, color) {
    const {
      graph,
      data,
      bubbleClickFun,
      valueFont,
      labelFont
    } = this.props;
   
    const bubbleChart = d3.select(this.svg).append("g")
      .attr("class", "bubble-chart")
      .attr("transform", function(d) { return "translate(" + (width * graph.offsetX) + "," + (width * graph.offsetY) + ")"; });;

    const node = bubbleChart.selectAll(".node")
    .data(nodes)
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .on("click", function(d) {
        bubbleClickFun(d.label);
    });
    
    

    node.append("circle")
      .attr("id", function(d) { return d.id; })
      .attr("r", function(d) { return d.r - (d.r * .04); })
      .style("fill", function(d) { return d.data.color ? d.data.color : color(nodes.indexOf(d)); })
      .style("z-index", 5)
      .on('mouseover', function(d) {
        d3.select(this).attr("r", d.r * 2.04);
      })
      .on('mouseout', function(d) {
        const r = d.r - (d.r * 0.04);
        d3.select(this).attr("r", r);
      });

    node.append("clipPath")
      .attr("id", function(d) { return "clip-" + d.id; })
      .append("use")
      .attr("xlink:href", function(d) { return "#" + d.id; });

    // node.append("text")
    //   .attr("class", "value-text")
    //   .style("font-size", `${valueFont.size}px`)
    //   .attr("clip-path", function(d) { return "url(#clip-" + d.id + ")"; })
    //   .style("font-weight", (d) => {
    //     return valueFont.weight ? valueFont.weight : 600;
    //   })
    //   .style("font-family", valueFont.family)
    //   .style("fill", () => {
    //     return valueFont.color ? valueFont.color : '#000';
    //   })
    //   .style("stroke", () => {
    //     return valueFont.lineColor ? valueFont.lineColor : '#000';
    //   })
    //   .style("stroke-width", () => {
    //     return valueFont.lineWeight ? valueFont.lineWeight : 0;
    //   })
    //   .text(function(d) { return d.value; });

    node.append("text")
      .attr("class", "label-text")
      .style("font-size", `${labelFont.size}px`)
      .attr("clip-path", function(d) { return "url(#clip-" + d.id + ")"; })
      .style("font-weight", (d) => {
        return labelFont.weight ? labelFont.weight : 600;
      })
      .style("font-family", labelFont.family)
      .style("fill", () => {
        return labelFont.color ? labelFont.color : '#000';
      })
      .style("stroke", () => {
        return labelFont.lineColor ? labelFont.lineColor : '#000';
      })
      .style("stroke-width", () => {
        return labelFont.lineWeight ? labelFont.lineWeight : 0;
      })
      .text(function(d) {
        return d.label;
      });


    // Center the texts inside the circles.
    d3.selectAll(".label-text").attr("x", function(d) {
      const self = d3.select(this);
      const width = self.node().getBBox().width;
      return -(width/2);
    })
    .style("opacity", function(d) {
      const self = d3.select(this);
      const width = self.node().getBBox().width;
      d.hideLabel = width*1.05 > (d.r*2);
      return d.hideLabel ? 0 : 1;
    })
    .attr("y", function(d) {
      return labelFont.size/2
    })

    // Center the texts inside the circles.
    d3.selectAll(".label-text").attr("x", function(d) {
      const self = d3.select(this);
      const width = self.node().getBBox().width;
      return -(width/2);
    })
    .attr("y", function(d) {
      if (!d.hideLabel) {
        return valueFont.size / 3;
      } else {
        return -valueFont.size * 0.5;
      }
    });

    node.append("title")
      .text(function(d) { return d.label; });
  }
  
  renderLegend(width, height, offset, nodes, color) {
    const {
      data,
      legendClickFun,
      legendFont,
    } = this.props;
    const bubble = d3.select('.bubble-chart');
    const bubbleHeight = bubble.node().getBBox().height;

    const legend = d3.select(this.svg).append("g")
      .attr("transform", function() { return `translate(${offset},${(bubbleHeight)* 0.05})`; })
      .attr("class", "legend");

    let textOffset = 0;
    const texts = legend.selectAll(".legend-text")
    .data(nodes)
    .enter()
    .append("g")
      .attr("transform", (d, i) => {
        const offset = textOffset;
        textOffset+= legendFont.size + 10;
        return `translate(0,${offset})`;
      })
      .on('mouseover', function(d) {
        d3.select('#' + d.id).attr("r", d.r * 1.04);
      })
      .on('mouseout', function(d) {
        const r = d.r - (d.r * 0.04);
        d3.select('#' + d.id).attr("r", r);
      })
      .on("click", function(d) {
        legendClickFun(d.label);
    });;

    texts.append("rect")
      .attr("width", 30)
      .attr("height", legendFont.size)
      .attr("x", 0)
      .attr("y", -legendFont.size)
      .style("fill", "transparent");

    texts.append("rect")
      .attr("width", legendFont.size)
      .attr("height", legendFont.size)
      .attr("x", 0)
      .attr("y", -legendFont.size)
      .style("fill", function(d) { return d.data.color ? d.data.color : color(nodes.indexOf(d)); });
      
      
    texts.append("text")
      .style("font-size", `${legendFont.size}px`)
      .style("font-weight", (d) => {
        return legendFont.weight ? legendFont.weight : 600;
      })
      .style("font-family", legendFont.family)
      .style("fill", () => {
        return legendFont.color ? legendFont.color : '#000';
      })
      .style("stroke", () => {
        return legendFont.lineColor ? legendFont.lineColor : '#000';
      })
      .style("stroke-width", () => {
        return legendFont.lineWeight ? legendFont.lineWeight : 0;
      })
      .attr("x", (d) => { return legendFont.size + 10 })
      .attr("y", 0)
      .text((d) => { return d.label });
  }
}

BubbleChart.propTypes = {
  overflow: PropTypes.bool,
  graph: PropTypes.shape({
    zoom: PropTypes.number,
    offsetX: PropTypes.number,
    offsetY: PropTypes.number,
  }),
  width: PropTypes.number,
  height: PropTypes.number,
  padding: PropTypes.number,
  showLegend: PropTypes.bool,
  legendPercentage: PropTypes.number,
  legendFont: PropTypes.shape({
    family: PropTypes.string,
    size: PropTypes.number,
    color: PropTypes.string,
    weight: PropTypes.string,
  }),
  valueFont: PropTypes.shape({
    family: PropTypes.string,
    size: PropTypes.number,
    color: PropTypes.string,
    weight: PropTypes.string,
  }),
  labelFont: PropTypes.shape({
    family: PropTypes.string,
    size: PropTypes.number,
    color: PropTypes.string,
    weight: PropTypes.string,
  }),
}
BubbleChart.defaultProps = {
  overflow: false,
  graph: {
    zoom: 1.1,
    offsetX: -0.05,
    offsetY: -0.01,
  },
  width: 1000,
  height: 800,
  padding: 0,
  showLegend: true,
  legendPercentage: 20,
  legendFont: {
    family: 'Arial',
    size: 12,
    color: '#000',
    weight: 'bold',
  },
  valueFont: {
    family: 'Arial',
    size: 16,
    color: '#fff',
    weight: 'bold',
  },
  labelFont: {
    family: 'Arial',
    size: 11,
    color: '#fff',
    weight: 'normal',
  },
  
  bubbleClickFun: (label) => {console.log(`Bubble ${label} is clicked ...`)
  },
  legendClickFun: (label) => {console.log(`Legend ${label} is clicked ...`)}
}
import React,{Component}来自'React';
从“react dom”导入react dom;
从“道具类型”导入道具类型;
从“d3”导入*作为d3;
从“d3”导入提示;
导出默认类BubbleChart扩展组件{
建造师(道具){
超级(道具);
this.renderChart=this.renderChart.bind(this);
this.renderBubbles=this.renderBubbles.bind(this);
this.renderLegend=this.renderLegend.bind(this);
}
componentDidMount(){
this.svg=ReactDOM.findDOMNode(this);
这个.renderChart();
}
componentDidUpdate(){
常数{
宽度,
高度,
}=这是道具;
如果(宽度!==0和高度!==0){
这个.renderChart();
}
}
render(){
常数{
宽度,
高度,
}=这是道具;
返回(
)
}
renderChart(){
常数{
溢流
图表
数据,
高度,
宽度,
衬垫,
传奇人物,
传说中的百分比,
}=这是道具;
//将svg元素重置为空状态。
this.svg.innerHTML='';
//如果props(overflow)为true,则允许气泡在视觉方面溢出其SVG容器。
如果(溢出)
this.svg.style.overflow=“可见”;
常量bubblesWidth=showLegend?宽度*(1-(legendPercentage/100)):宽度;
常量legendWidth=宽度-气泡宽度;
常量color=d3.scaleOrdinal(d3.schemeCategory20c);
const pack=d3.pack()
.size([bubblesWidth*graph.zoom,bubblesWidth*graph.zoom])
.填充(填充);
//处理数据,使其具有层次结构;
const root=d3.hierarchy({children:data})
.sum(函数(d){返回d.value;})
.sort(函数(a,b){返回b.value-a.value;})
.每个((d)=>{
if(d.数据标签){
d、 label=d.data.label;
d、 id=d.data.label.toLowerCase().replace(/| \//g,“-”);
}
});
//将数据传递到包布局以计算分布。
const nodes=pack(root).leaves();
//调用绘制气泡的函数。
此.renderBubbles(气泡宽度、节点、颜色);
//调用绘制图例的函数。
如果(显示图例){
renderGend(legendWidth、height、bubblesWidth、nodes、color);
}
}
渲染气泡(宽度、节点、颜色){
常数{
图表
数据,
泡泡糖很有趣,
valueFont,
拉贝尔丰
}=这是道具;
const bubbleChart=d3.select(this.svg.append(“g”)
.attr(“类”、“气泡图”)
.attr(“transform”,函数(d){return”translate(“+(width*graph.offsetX)+)”,“+(width*graph.offsetY)+”);;
const node=bubbleChart.selectAll(“.node”)
.数据(节点)
.enter().append(“g”)
.attr(“类”、“节点”)
.attr(“transform”,函数(d){return“translate”(“+d.x+”,“+d.y+”)”);})
.打开(“单击”,功能(d){
bubbleClickFun(d.label);
});
node.append(“圆”)
.attr(“id”,函数(d){return d.id;})
.attr(“r”,函数(d){返回d.r-(d.r*.04);})
.style(“fill”,函数(d){返回d.data.color?d.data.color:color(nodes.indexOf(d));})
.风格(“z指数”,5)
.on('mouseover',函数(d){
d3.选择(本).attr(“r”,d.r*2.04);
})
.on('mouseout',函数(d){
常数r=d.r-(d.r*0.04);
d3.选择(this).attr(“r”,r);
});
node.append(“clipPath”)
.attr(“id”,函数(d){return“clip-”+d.id;})
.append(“使用”)
.attr(“xlink:href”,函数(d){return“#”+d.id;});
//node.append(“文本”)
//.attr(“类”、“值文本”)
//.style(“字体大小”,“${valueFont.size}px`)
//.attr(“clip path”,函数(d){return”url(#clip-“+d.id+”);})
//.style(“字体重量”,(d)=>{
//返回值font.weight?值font.weight:600;
//   })
//.style(“字体系列”,valueFont.family)
//.style(“填充”,()=>{
//返回valueFont.color?valueFont.color:“#000”;
//   })
//.style(“笔划”,()=>{
//返回valueFont.lineColor?valueFont.lineColor:“#000”;
//   })
//.style(“笔划宽度”,()=>{
//返回值font.lineWeight?valueFont.lineWeight:0;
//   })
//.text(函数(d){返回d.value;});
node.append(“文本”)
.attr(“类”、“标签文本”)
.style(“字体大小”,“${labelFont.size}px`”)
.attr(“clip path”,函数(d){return”url(#clip-“+d.id+”);})
.style(“字体重量”,(d)=>{
返回labelFont.weight?labelFont.weight:600;
})
.style(“字体系列”,labelFont.family)
.style(“填充”,()=>{
返回labelFont.color?labelFont.color:“#000”;
})
.style(“笔划”,()=>{
返回labelFont.lineColor?labelFont.lineColor:“#000”;
})
.style(“笔划宽度”,()=>{
返回labelFont.lineWeight?labelFont.lineWeight:0;
})
.文本(功能(d){
返回d.标签;
});
//将文本置于圆圈内的中心。
d3.选择全部(“.label text”).attr(“x”,函数(d){
const self=d3.选择(此);
const width=self.node().getBBox().width;
返回-(宽度/2);
})
.样式(“不透明度”,函数(d){
const self=d3.选择(此);
const width=self.node().getBBox().width;
d、 hideLabel=宽度*1.05>(d.r*2);
返回d.hideLabel?0:1;
})
.attr(“y”,函数(d){
返回labelFont.size/2
})
//将文本置于圆圈内的中心。
d3.选择全部(“.label text”).attr(“x”,函数(d){
const self=d3.选择(此);
const width=self.node().getBBox().width;
返回-(宽度/2);
})
.attr(“y”,函数(d){
如果(!d.hideLabel){
返回值font.size/3;
}否则{
返回-valueFont.size*0.5;
}
});
node.append(“标题”)
.text(函数(d){返回d。