我有一张图表,我正在尝试提高用户友好性,并且我一直在尝试添加一件事情,其他问题出现了问题。
我想要完成的是:图表以“悬停”状态开始。当其中一个悬停时,它有一个边框以及图表中间的文本更新标签和百分比。我还希望背景是一个SVG图像(如果不可能的话,这不重要)。
我做了fiddle - 我也想删除工具提示。
任何帮助将不胜感激!
IMG想要实现的目标:
我的HTML代码:
<div id="doughnutChart" class="chart"></div>
的jQuery
jQuery(function(){
jQuery("#doughnutChart").drawDoughnutChart([
{ title: "Holiday Fund", value : 5, color: "#2C3E50" },
{ title: "Emergencies", value: 20, color: "#FC4349" },
{ title: "Loans", value: 20, color: "#6DBCDB" },
{ title: "Widows", value : 27, color: "#F7E248" },
{ title: "Medical Support", value : 28, color: "#D7DADB" },
]);
});
/*!
* jquery.drawDoughnutChart.js
* Version: 0.4.1(Beta)
* Inspired by Chart.js(http://www.chartjs.org/)
*
* Copyright 2014 hiro
* https://github.com/githiro/drawDoughnutChart
* Released under the MIT license.
*
*/
;(function($, undefined) {
$.fn.drawDoughnutChart = function(data, options) {
var $this = this,
W = $this.width(),
H = $this.height(),
centerX = W/2,
centerY = H/2,
cos = Math.cos,
sin = Math.sin,
PI = Math.PI,
settings = $.extend({
segmentShowStroke : true,
segmentStrokeColor : "#0C1013",
segmentStrokeWidth : 1,
baseColor: "rgba(0,0,0,0.5)",
baseOffset: 4,
edgeOffset : 10,//offset from edge of $this
percentageInnerCutout : 75,
animation : true,
animationSteps : 90,
animationEasing : "easeInOutExpo",
animateRotate : true,
tipOffsetX: -8,
tipOffsetY: -45,
tipClass: "doughnutTip",
summaryClass: "doughnutSummary",
summaryTitle: "",
summaryTitleClass: "doughnutSummaryTitle",
summaryNumberClass: "doughnutSummaryNumber",
beforeDraw: function() { },
afterDrawed : function() { },
onPathEnter : function(e,data) { },
onPathLeave : function(e,data) { }
}, options),
animationOptions = {
linear : function (t) {
return t;
},
easeInOutExpo: function (t) {
var v = t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t;
return (v>1) ? 1 : v;
}
},
requestAnimFrame = function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}();
settings.beforeDraw.call($this);
var $svg = $('<svg width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>').appendTo($this),
$paths = [],
easingFunction = animationOptions[settings.animationEasing],
doughnutRadius = Min([H / 2,W / 2]) - settings.edgeOffset,
cutoutRadius = doughnutRadius * (settings.percentageInnerCutout / 100),
segmentTotal = 0;
//Draw base doughnut
var baseDoughnutRadius = doughnutRadius + settings.baseOffset,
baseCutoutRadius = cutoutRadius - settings.baseOffset;
$(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"d": getHollowCirclePath(baseDoughnutRadius, baseCutoutRadius),
"fill": settings.baseColor
})
.appendTo($svg);
//Set up pie segments wrapper
var $pathGroup = $(document.createElementNS('http://www.w3.org/2000/svg', 'g'));
$pathGroup.attr({opacity: 0}).appendTo($svg);
//Set up tooltip
var $tip = $('<div class="' + settings.tipClass + '" />').appendTo('body').hide(),
tipW = $tip.width(),
tipH = $tip.height();
for (var i = 0, len = data.length; i < len; i++) {
segmentTotal += data[i].value;
$paths[i] = $(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"stroke-width": settings.segmentStrokeWidth,
"stroke": settings.segmentStrokeColor,
"fill": data[i].color,
"data-order": i,
"class": 'counter-'+i
})
.appendTo($pathGroup)
.on("mouseenter", pathMouseEnter)
.on("mouseleave", pathMouseLeave)
.on("mousemove", pathMouseMove);
}
//Set up center text area
var summarySize = (cutoutRadius - (doughnutRadius - cutoutRadius)) * 2,
$summary = $('<div class="' + settings.summaryClass + '" />')
.appendTo($this)
.css({
width: summarySize + "px",
height: summarySize + "px",
"margin-left": -(summarySize / 2) + "px",
"margin-top": -(summarySize / 2) + "px"
});
var $summaryTitle = $('<p class="' + settings.summaryTitleClass + '">' + data[0].title + "<br />" + data[0].value + '%' + '</p>').appendTo($summary);
//var $summaryNumber = $('<p class="' + settings.summaryNumberClass + '"></p>').appendTo($summary).css({opacity: 0});
//Animation start
animationLoop(drawPieSegments);
//Functions
function getHollowCirclePath(doughnutRadius, cutoutRadius) {
//Calculate values for the path.
//We needn't calculate startRadius, segmentAngle and endRadius, because base doughnut doesn't animate.
var startRadius = -1.570,// -Math.PI/2
segmentAngle = 6.2831,// 1 * ((99.9999/100) * (PI*2)),
endRadius = 4.7131,// startRadius + segmentAngle
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,
'A', doughnutRadius, doughnutRadius, 0, 1, 1, endX, endY,//Draw outer circle
'Z',//Close path
'M', startX2, startY2,//Move pointer
'A', cutoutRadius, cutoutRadius, 0, 1, 0, endX2, endY2,//Draw inner circle
'Z'
];
cmd = cmd.join(' ');
return cmd;
};
function pathMouseEnter(e) {
var order = $(this).data().order;
$tip.text(data[order].title + ": " + data[order].value)
.fadeIn(200);
settings.onPathEnter.apply($(this),[e,data]);
$('.doughnutSummaryTitle').html(data[order].title + "<br />" + data[order].value + '%')
}
function pathMouseLeave(e) {
$tip.hide();
settings.onPathLeave.apply($(this),[e,data]);
}
function pathMouseMove(e) {
$tip.css({
top: e.pageY + settings.tipOffsetY,
left: e.pageX - $tip.width() / 2 + settings.tipOffsetX
});
}
function drawPieSegments (animationDecimal) {
var startRadius = -PI / 2,//-90 degree
rotateAnimation = 1;
if (settings.animation && settings.animateRotate) rotateAnimation = animationDecimal;//count up between0~1
//drawDoughnutText(animationDecimal, segmentTotal);
$pathGroup.attr("opacity", animationDecimal);
//If data have only one value, we draw hollow circle(#1).
if (data.length === 1 && (4.7122 < (rotateAnimation * ((data[0].value / segmentTotal) * (PI * 2)) + startRadius))) {
$paths[0].attr("d", getHollowCirclePath(doughnutRadius, cutoutRadius));
return;
}
for (var i = 0, len = data.length; i < len; i++) {
var segmentAngle = rotateAnimation * ((data[i].value / segmentTotal) * (PI * 2)),
endRadius = startRadius + segmentAngle,
largeArc = ((endRadius - startRadius) % (PI * 2)) > PI ? 1 : 0,
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,//Move pointer
'A', doughnutRadius, doughnutRadius, 0, largeArc, 1, endX, endY,//Draw outer arc path
'L', startX2, startY2,//Draw line path(this line connects outer and innner arc paths)
'A', cutoutRadius, cutoutRadius, 0, largeArc, 0, endX2, endY2,//Draw inner arc path
'Z'//Cloth path
];
$paths[i].attr("d", cmd.join(' '));
startRadius += segmentAngle;
}
}
//function drawDoughnutText(animationDecimal, segmentTotal) {
// $summaryNumber
// .css({opacity: animationDecimal})
// .text((segmentTotal * animationDecimal).toFixed(1));
//}
function animateFrame(cnt, drawData) {
var easeAdjustedAnimationPercent =(settings.animation)? CapValue(easingFunction(cnt), null, 0) : 1;
drawData(easeAdjustedAnimationPercent);
}
function animationLoop(drawData) {
var animFrameAmount = (settings.animation)? 1 / CapValue(settings.animationSteps, Number.MAX_VALUE, 1) : 1,
cnt =(settings.animation)? 0 : 1;
requestAnimFrame(function() {
cnt += animFrameAmount;
animateFrame(cnt, drawData);
if (cnt <= 1) {
requestAnimFrame(arguments.callee);
} else {
settings.afterDrawed.call($this);
}
});
}
function Max(arr) {
return Math.max.apply(null, arr);
}
function Min(arr) {
return Math.min.apply(null, arr);
}
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function CapValue(valueToCap, maxValue, minValue) {
if (isNumber(maxValue) && valueToCap > maxValue) return maxValue;
if (isNumber(minValue) && valueToCap < minValue) return minValue;
return valueToCap;
}
return $this;
};
})(jQuery);
CSS
.chart {
position: absolute;
width: 450px;
height: 450px;
top: 50%;
left: 50%;
margin: -225px 0 0 -225px;
}
.doughnutTip {
position: absolute;
min-width: 30px;
max-width: 300px;
padding: 5px 15px;
border-radius: 1px;
background: rgba(0,0,0,.8);
color: #ddd;
font-size: 17px;
text-shadow: 0 1px 0 #000;
text-transform: uppercase;
text-align: center;
line-height: 1.3;
letter-spacing: .06em;
box-shadow: 0 1px 3px rgba(0,0,0,0.5);
pointer-events: none;
&::after {
position: absolute;
left: 50%;
bottom: -6px;
content: "";
height: 0;
margin: 0 0 0 -6px;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
border-top: 6px solid rgba(0,0,0,.7);
line-height: 0;
}
}
.doughnutSummary {
position: absolute;
top: 50%;
left: 50%;
color: #000;
text-align: center;
text-shadow: 0 -1px 0 #111;
cursor: default;
}
.doughnutSummaryTitle {
position: absolute;
top: 50%;
width: 100%;
margin-top: -27%;
font-size: 22px;
letter-spacing: .06em;
}
.doughnutSummaryNumber {
position: absolute;
top: 50%;
width: 100%;
margin-top: -15%;
font-size: 55px;
}
.chart path:hover { opacity: 0.65; }
答案 0 :(得分:3)
如果不修改原始插件drawDoughnutChart
,您可以覆盖默认设置。
对于out笔划,您可以绘制另一个图表,隐藏它,并使用插件公开的afterDrawed
,onPathEnter
,onPathLeave
回调来执行逻辑。
对于每个饼图片段的背景,您可以使用svg pattern
。
Javascript :
var firstSelected = 0;
var seed = [
{ title: "Holiday Fund", value : 5, color: "url(#dots2)" },
{ title: "Emergencies", value: 20, color: "url(#diagonal1)" },
{ title: "Loans", value: 20, color: "url(#dots1)" },
{ title: "Widows", value : 27, color: "url(#diagonal2)" },
{ title: "Medical Support", value : 28, color: "url(#hatch1)" },
];
var seed2 = [
{ value : 5, color: "#9fa1ac" },
{ value: 20, color: "#ef5123" },
{ value: 20, color: "#ef5123" },
{ value : 27, color: "#9fa1ac" },
{ value : 28, color: "#ef5123" },
];
var chartOptions = {
baseOffset: 0,
segmentShowStroke : false,
segmentStrokeColor : 'transparent',
baseColor: 'transparent',
percentageInnerCutout : 60,
onPathEnter: function (e, data) {
var order = $(this).data().order;
$('#doughnutChart .doughnutSummaryTitle').html(data[order].title);
$('#doughnutChart .doughnutSummaryNumber').html(data[order].value + '%');
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutBg g').find('path:eq('+(order)+')').fadeIn(500)
},
onPathLeave: function (e, data) {
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutChart .doughnutSummary').hide();
},
afterDrawed : function () {
$('#doughnutChart .doughnutSummaryTitle').html(seed[firstSelected].title);
$('#doughnutChart .doughnutSummaryNumber').html(seed[firstSelected].value + '%');
$('#doughnutChart .doughnutSummary').css({width: '160px', height: '60px', marginLeft: '-80px', marginTop: '-30px'});
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path:eq('+firstSelected+')').fadeIn(500);
}
} ;
var chartOptions2 = {
baseOffset: 0,
segmentStrokeColor : 'transparent',
segmentShowStroke : false,
percentageInnerCutout : 95
} ;
jQuery("#doughnutChart").drawDoughnutChart(seed, chartOptions);
jQuery("#doughnutBg").drawDoughnutChart(seed2, chartOptions2);
CSS :
.chart {
position: absolute;
width: 400px;
height: 400px;
top: 50%;
left: 50%;
margin: -200px 0 0 -200px;
}
.bgchart {
position: absolute;
width: 430px;
height: 430px;
top: 50%;
left: 50%;
margin: -215px 0 0 -215px;
}
.chart .doughnutSummary,
.bgchart .doughnutSummary{
display: none;
}
.chart path:hover { opacity: 0.65; }
.bgchart path { display: none }
<强> HTML 强>:
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="hatch1" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#ef5123; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="hatch2" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#9fa1ac; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="diagonal1" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="diagonal2" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#9fa1ac;" />
</pattern>
<pattern id="dots1" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="dots2" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#9fa1ac;" />
</pattern>
</defs>
</svg>
<div class="bgchart" id="doughnutBg"></div>
<div class="chart" id="doughnutChart"></div>