我在Codepen上找到了一些代码表(代码:Henry Poydar),它使用snap.svg创建动画规范图表。
angular.module('app', []);
angular.module('app')
.controller('metricsCtrl', function($scope) {
$scope.percentage = .8;
var polar_to_cartesian, svg_circle_arc_path, animate_arc;
polar_to_cartesian = function(cx, cy, radius, angle) {
var radians;
radians = (angle - 90) * Math.PI / 180.0;
return [Math.round((cx + (radius * Math.cos(radians))) * 100) / 100, Math.round((cy + (radius * Math.sin(radians))) * 100) / 100];
};
svg_circle_arc_path = function(x, y, radius, start_angle, end_angle) {
var end_xy, start_xy;
start_xy = polar_to_cartesian(x, y, radius, end_angle);
end_xy = polar_to_cartesian(x, y, radius, start_angle);
return "M " + start_xy[0] + " " + start_xy[1] + " A " + radius + " " + radius + " 0 0 0 " + end_xy[0] + " " + end_xy[1];
};
animate_arc = function(ratio, svg, perc) {
var arc;
arc = svg.path('');
return Snap.animate(0, ratio, (function(val) {
var path;
arc.remove();
path = svg_circle_arc_path(500, 500, 450, -90, val * 180.0 - 90);
arc = svg.path(path);
arc.attr({
class: 'data-arc'
});
perc.text(Math.round(val * 100) + '%');
}), Math.round(2000 * ratio), mina.easeinout);
};
$scope.$watch('percentage', function() {
$('.metric').each(function() {
var ratio, svg, perc;
//ratio = $(this).data('ratio');
ratio = $scope.percentage;
svg = Snap($(this).find('svg')[0]);
perc = $(this).find('text.percentage');
animate_arc(ratio, svg, perc);
});
});
});

.metric {
padding: 10%;
}
.metric svg {
max-width: 100%;
}
.metric path {
stroke-width: 75;
stroke: #ecf0f1;
fill: none;
}
.metric path.data-arc {
stroke: #3498db;
}
.metric text {
fill: #3498db;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<div ng-app="app" ng-controller="metricsCtrl">
<div class="metric">
<svg viewBox="0 0 1000 500">
<path d="M 950 500 A 450 450 0 0 0 50 500"></path>
<text class='percentage' text-anchor="middle" alignment-baseline="middle" x="500" y="300" font-size="140" font-weight="bold">0%
</text>
<text class='title' text-anchor="middle" alignment-baseline="middle" x="500" y="450" font-size="90" font-weight="normal">Empty
</text>
</svg>
</div>
<input ng-model="percentage">
</div>
&#13;
我希望能够动态更新图表数据并相应地进行SVG渲染。我能够让图表显示增加值,但价值下降不起作用。这是一个重现我的问题http://codepen.io/EvanWieland/pen/bpxqpV的演示。在演示中,如果您在图表下方的输入中增加值然后减少它,您将能够观察到我的困境。请注意,演示使用Angularjs,这不是必需的。先谢谢!
答案 0 :(得分:1)
这是由于“svg.path(path)”每次创建一个新的弧,因此减少的值会绘制一个前一个隐藏的弧。解决方案是在每次重绘时删除先前的弧。
angular.module('app', []);
angular.module('app')
.controller('metricsCtrl', function($scope) {
$scope.percentage = .8;
var polar_to_cartesian, svg_circle_arc_path, animate_arc;
polar_to_cartesian = function(cx, cy, radius, angle) {
var radians;
radians = (angle - 90) * Math.PI / 180.0;
return [Math.round((cx + (radius * Math.cos(radians))) * 100) / 100, Math.round((cy + (radius * Math.sin(radians))) * 100) / 100];
};
svg_circle_arc_path = function(x, y, radius, start_angle, end_angle) {
var end_xy, start_xy;
start_xy = polar_to_cartesian(x, y, radius, end_angle);
end_xy = polar_to_cartesian(x, y, radius, start_angle);
return "M " + start_xy[0] + " " + start_xy[1] + " A " + radius + " " + radius + " 0 0 0 " + end_xy[0] + " " + end_xy[1];
};
animate_arc = function(ratio, svg, perc) {
var arc;
arc = svg.path('');
return Snap.animate(0, ratio, (function(val) {
var path;
arc.remove();
path = svg_circle_arc_path(500, 500, 450, -90, val * 180.0 - 90);
var previousArc = svg.select('.data-arc')
if (previousArc){
previousArc.remove(); // REMOVES PREVIOUS ARC
}
arc = svg.path(path);
arc.attr({
class: 'data-arc'
});
perc.text(Math.round(val * 100) + '%');
}), Math.round(2000 * ratio), mina.easeinout);
};
$scope.$watch('percentage', function() {
$('.metric').each(function() {
var ratio, svg, perc;
//ratio = $(this).data('ratio');
ratio = $scope.percentage;
svg = Snap($(this).find('svg')[0]);
perc = $(this).find('text.percentage');
animate_arc(ratio, svg, perc);
});
});
});
.metric {
padding: 10%;
}
.metric svg {
max-width: 100%;
}
.metric path {
stroke-width: 75;
stroke: #ecf0f1;
fill: none;
}
.metric path.data-arc {
stroke: #3498db;
}
.metric text {
fill: #3498db;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<div ng-app="app" ng-controller="metricsCtrl">
<div class="metric">
<svg viewBox="0 0 1000 500">
<path d="M 950 500 A 450 450 0 0 0 50 500"></path>
<text class='percentage' text-anchor="middle" alignment-baseline="middle" x="500" y="300" font-size="140" font-weight="bold">0%
</text>
<text class='title' text-anchor="middle" alignment-baseline="middle" x="500" y="450" font-size="90" font-weight="normal">Empty
</text>
</svg>
</div>
<input ng-model="percentage">
</div>