2016-11-20 29 views
1

我正在创建饼图。D3,应用viewBox时的工具提示位置

将鼠标悬停段,我想显示自定义的HTML工具提示...

所有从一开始的时候,我用d3.event.pageXd3.event.pageY计算工具提示的位置。

但现在我想在扇形的中心点,以显示工具提示

enter image description here

所以,我悬停

var centroid = arcs.pie.centroid(d); 
      var left = centroid[0]; 
      var top = centroid[1]; 

计算重心,并相应分配工具提示的左,右位置

tooltip.style("left", (left) + "px") 
     .style("top", (top) + "px"); 

只有工作原理,当图表的大小是初始的,但我也希望图表响应SVG的

var svg = d3.select(selector) 
     .append('svg') 
     .attr("viewBox", "0 0 " + attrs.svgWidth + " " + attrs.svgHeight) 
     .attr("preserveAspectRatio", "xMidYMid meet") 

这里

所以,我已经指派视框财产问题来了:

调整当窗口,图表会相应地缩放,但工具提示位置不在区段中心。

我该如何将此工具提示移动到正确的位置?

我在寻找“无插件”解决方案。

退房codepen

回答

1

夫妇计算需要在这里。首先,在获得质心后,需要将其解开,因为它们在g变换中(并且您的div需要定位到顶部/左侧)。然后,您可以简单地获取svg的当前/实际宽度/高度,并将其比例缩放到初始非视图框宽度/高度。

var centroid = arcs.pie.centroid(d), 
    svgDim = svg.node().getBoundingClientRect(); 

var left = (centroid[0] + dynamic.marginLeft) * (svgDim.width/attrs.svgWidth), 
    top = (centroid[1] + dynamic.marginTop) * (svgDim.height/attrs.svgHeight); 

下面是完整的运行代码:

function packData(p) { 
 
    var data = p; 
 
    var result = { 
 
    title: data.datasets[0].label, 
 
    data: [] 
 
    }; 
 

 
    data.labels.forEach(function(v) { 
 
    result.data.push({ 
 
     label: v 
 
    }); 
 
    }); 
 

 
    result.data.forEach(function(v, i) { 
 
    v.value = data.datasets[0].data[i]; 
 

 
    if (data.datasets[0].backgroundColor) { 
 
     v.backgroundColor = data.datasets[0].backgroundColor[i]; 
 
    } 
 

 
    if (data.extras) { 
 
     for (var attrname in data.extras[i]) { 
 
     v[attrname] = data.extras[i][attrname]; 
 
     } 
 
    } 
 
    }); 
 

 
    return result; 
 

 
} 
 

 
var svg; 
 

 
function drawD3JsPie(selector) { 
 

 
    var info = packData({ 
 
    labels: ["Niger", "Cameroon", "Georgia", "Spain", "United States", "Singapore", "Qatar"], 
 
    datasets: [{ 
 
     label: 'GDP Per Capita in $ (2015)', 
 
     data: [1080, 3144, 9630, 34819, 55805, 85253, 132099], 
 
     backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56", "#AA6384", "#2CA21B", "#678E86", "#FFAE86"] 
 
    }] 
 
    }); 
 
    var data = info.data; 
 
    // ######## hard coded and dynamically calculated attributes ####### 
 

 
    var attrs = { 
 
    svgWidth: 600, 
 
    svgHeight: 600, 
 
    marginLeft: 4, 
 
    marginBottom: 20, 
 
    marginRight: 4, 
 
    marginTop: 20, 
 
    textColor: '#7f7777', 
 
    fontSize: '13px', 
 
    pieStroke: 'white', 
 
    pieStrokeWidth: 3, 
 
    titleText: info.title, 
 
    hoverColorImpact: 1, 
 
    animationDuration: 1200, 
 
    animationEase: 'out', 
 
    titleHeight: 30, 
 
    tooltipTextColor: 'white', 
 
    tooltipBackgroundColor: 'black', 
 

 
    } 
 

 
    var dynamic = {} 
 
    dynamic.chartWidth = attrs.svgWidth - attrs.marginLeft - attrs.marginRight 
 
    dynamic.chartHeight = attrs.svgHeight - attrs.marginTop - attrs.marginBottom - attrs.titleHeight; 
 
    dynamic.pieOuterRadius = Math.min(dynamic.chartWidth, dynamic.chartHeight)/2; 
 
    dynamic.chartTopMargin = attrs.marginTop + attrs.titleHeight; 
 
    dynamic.marginLeft = attrs.marginLeft + dynamic.pieOuterRadius; 
 
    dynamic.marginTop = dynamic.chartTopMargin + dynamic.pieOuterRadius; 
 

 
    // ##############  SCALES  ######### 
 

 

 
    // ############## ARCS ############### 
 
    var arcs = {} 
 
    arcs.pie = d3.arc() 
 
    .outerRadius(dynamic.pieOuterRadius - 10) 
 
    .innerRadius(0); 
 

 

 
    // ##########  layouts ####### 
 
    var layouts = {}; 
 
    layouts.pie = d3.pie() 
 
    .sort(null) 
 
    .value(function(d) { 
 
     return d.value; 
 
    }); 
 

 

 
    //############### STARTUP ANIMATIONS ############### 
 
    var tweens = {} 
 

 
    tweens.pieIn = function(endData) { 
 
    var startData = { 
 
     startAngle: 0, 
 
     endAngle: 0 
 
    }; 
 
    var interpolation = d3.interpolate(startData, endData); 
 
    return function(currentData) { 
 
     return arcs.pie(interpolation(currentData)); 
 
    } 
 
    }; 
 

 

 
    // ########### RESPONSIVE SVG DRAWING ############## 
 
    svg = d3.select(selector) 
 
    .append('svg') 
 
    .attr("viewBox", "0 0 " + attrs.svgWidth + " " + attrs.svgHeight) 
 
    .attr("preserveAspectRatio", "xMidYMid meet") 
 

 

 

 
    // ################# CHART CONTENT DRAWING ############### 
 

 
    var chart = svg.append('g') 
 
    .attr('width', dynamic.chartWidth) 
 
    .attr('height', dynamic.chartHeight) 
 
    .attr('transform', 'translate(' + (dynamic.marginLeft) + ',' + (dynamic.marginTop) + ')'); 
 

 

 
    var pieArcs = chart.selectAll('.arc') 
 
    .data(layouts.pie(data)) 
 
    .enter() 
 
    .append("g") 
 
    .attr("class", "arc"); 
 

 

 
    pieArcs.append("path") 
 
    //.attr("d", arcs.pie) 
 
    .attr('stroke-width', attrs.pieStrokeWidth) 
 
    .attr('stroke', attrs.pieStroke) 
 
    .attr("fill", function(d) { 
 
     return d.data.backgroundColor; 
 
    }) 
 
    .transition() 
 
    .duration(1000) 
 
    .attrTween("d", tweens.pieIn); 
 

 

 

 

 

 

 
    // ################ ADDING TOOLTIP ################## 
 
    var div = d3.select(selector) 
 
    .append("div") 
 
    .attr("class", "tooltip") 
 
    .style("opacity", 0) 
 
    .style("position", 'absolute') 
 
    .style("text-align", 'left') 
 
    .style("font", '12px sans-serif') 
 
    .style("background", attrs.tooltipBackgroundColor) 
 
    .style("padding", '5px') 
 
    .style("color", attrs.tooltipTextColor) 
 
    .style("border", '0px') 
 
    .style("border-radius", '4px') 
 
    .style("pointer-events", 'none') 
 

 
    d3.selectAll('.arc') 
 
    .on("mouseover", function(d, i) { 
 
     var centroid = arcs.pie.centroid(d), 
 
     svgDim = svg.node().getBoundingClientRect(); 
 

 
     var left = (centroid[0] + dynamic.marginLeft) * (svgDim.width/attrs.svgWidth), 
 
     top = (centroid[1] + dynamic.marginTop) * (svgDim.height/attrs.svgHeight); 
 

 
     d3.select(this) 
 
     .append('circle') 
 
     .style('fill', 'steelblue') 
 
     .attr("transform", "translate(" + centroid + ")") 
 
     .attr("r", 10); 
 

 
     var buffer = d.value.toString().length; 
 
     if (i > data.length/2) { 
 
     buffer = -buffer - 180; 
 
     } else { 
 
     buffer *= 4; 
 
     } 
 
     div.transition() 
 
     .duration(100) 
 
     .style("opacity", .9); 
 

 
     div.html("<b>" + attrs.titleText + "</b><br/>" + d.data.label + ' : ' + d.data.value) 
 
     .style("left", (left) + "px") 
 
     .style("top", (top) + "px"); 
 

 
     var currPath = d3.select(this).select('path'); 
 
     var darkenedColor = d3.rgb(currPath.attr('fill')).darker(attrs.hoverColorImpact); 
 
     currPath.attr('fill', darkenedColor); 
 

 

 
    }) 
 
    .on("mouseout", function(d) { 
 

 

 
     div.transition() 
 
     .duration(200) 
 
     .style("opacity", 0); 
 

 
     var currPath = d3.select(this).select('path'); 
 
     var changedColor = d3.rgb(currPath.attr('fill')).darker(-attrs.hoverColorImpact); 
 
     currPath.attr('fill', changedColor); 
 

 
    }); 
 

 

 

 

 
} 
 

 
drawD3JsPie("#d3JsPie");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script> 
 
<div style='height:50%;width:50%'id="d3JsPie"></div>

+0

非常感谢你 – bumbeishvili