效果
双轨迹旋转Chart实现思路
因工作关系,首先想到使用TWaver的矢量图定制,这样可以减少很多工作量,当然使用Canvas也可以实现同样的效果。
记得以前写过一个流动线条攻击效果,用来表示网络安全态势攻击,echart也有相应实现,效果如图:
记得当时的思路是,用一次绘制很多个小圈圈,通过渐变,透明度等设置,来模拟轨迹的效果。然而这种方法的致命缺点就是效率问题。
function FlowLink() {
FlowLink.superClass.constructor.apply(this, arguments);
}
twaver.Util.ext(FlowLink, twaver.Link, {
getVectorUIClass: function() {
return FlowLinkUI;
},
playAnimate: function(dur) {
this.animate.play();
},
setAnimate: function(dur) {
var dur = dur || 1200;
var self = this;
var fNode, tNode;
fNode = self.getFromNode();
tNode = self.getToNode();
this.animate = new twaver.Animate({
from: 0,
to: 1,
repeat: Number.POSITIVE_INFINITY,
// repeat: 2,
reverse: false,
dur: dur,
onPlay: function() {
},
onUpdate: function(value) {
self.setClient('percent', value);
if (value >= 1) self.setClient('over', true);
else self.setClient('over', false);
},
onDone: function() {
}
});
}
});
function FlowLinkUI() {
FlowLinkUI.superClass.constructor.apply(this, arguments);
}
twaver.Util.ext(FlowLinkUI, twaver.vector.LinkUI, {
paintBody: function(ctx) {
var link = this.getElement();
if (link.getClient('over')) return;
var fillColor = link.getClient('fillColor');
var shadowColor = link.getClient('shadowColor');
var tail = link.getClient('tail');
var percent = link.getClient('percent');
var paths = this.getLinkPoints();
var offset = this.getLineLength() * percent;
var tailFactor = link.getClient('tailFactor') || 1.5;
var tailRadius = link.getClient('tailRadius') || 2;
var point;
var fromPoint = this._element.getFromAgent().getCenterLocation();
var toPoint = this._element.getToAgent().getCenterLocation();
var point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset, 0).point;
var points = new twaver.List();
points.add(fromPoint);
points.add(point);
if (link.getClient('controlPointX')) {
var controlPoint = {
x: link.getClient('controlPointX'),
y: link.getClient('controlPointY')
};
var c1 = {
x: (fromPoint.x + controlPoint.x) / 2,
y: (fromPoint.y + controlPoint.y) / 2
};
var c2 = {
x: (toPoint.x + controlPoint.x) / 2,
y: (toPoint.y + controlPoint.y) / 2
};
var c3 = {
x: (c1.x + c2.x) / 2,
y: (c1.y + c2.y) / 2
};
points.add(c1);
points.add(c2);
points.add(c3);
// points.add(controlPoint);
}
var rect = _twaver.math.getRect(points);
if (fromPoint.x < toPoint.x) {
ctx.rect(rect.x, rect.y, Math.abs(point.x - fromPoint.x) + 1.5, rect.height);
} else {
ctx.rect(point.x - 1.5, rect.y, Math.abs(point.x - fromPoint.x), rect.height);
}
ctx.clip();
FlowLinkUI.superClass.paintBody.call(this, ctx);
for (var i = 0, count = tail; i < count; i++) {
var v = i / count;
point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset - (count - i) *
tailFactor, 0).point;
ctx.globalAlpha = v * v;
ctx.shadowBlur = 10;
ctx.shadowColor = shadowColor;
ctx.beginPath();
ctx.fillStyle = fillColor;
ctx.arc(point.x, point.y, tailRadius, 0, Math.PI * 2, false);
ctx.fill();
}
for (var i = 0, count = tail; i < count; i++) {
var v = i / count;
point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset - (count - i) * 1,
0).point;
ctx.globalAlpha = v * v;
ctx.shadowBlur = 1;
ctx.shadowColor = shadowColor;
ctx.beginPath();
ctx.fillStyle = 'white';
ctx.arc(point.x, point.y, 1, 0, Math.PI * 2, false);
ctx.fill();
}
}
});
点击查看效果
使用globalCompositeOperation方法
var canvas = this.canvas,
g = this.g,
gradient = this.gradient,
gradient2 = this.gradient2,
diameter = Math.floor(data.getWidth() * view.getZoom()),
radius = diameter / 2,
hueStart = 120,
hueEnd = 170,
hueDiff = Math.abs(hueEnd - hueStart),
width = diameter,
height = diameter;
if (!canvas) {
this.canvas = canvas = document.createElement('canvas');
}
if (width !== canvas.width || height !== canvas.height) {
canvas.width = diameter;
canvas.height = diameter;
this.g = g = canvas.getContext('2d');
this.gradient = gradient = g.createLinearGradient(radius, 0, 0, 0);
gradient.addColorStop(0, 'hsla(' + hueStart + ', ' + 50 + '%, ' + 40 + '%, 1.0)');
gradient.addColorStop(1, 'hsla(' + hueEnd + ', ' + 50 + '%, ' + 40 + '%, 0.1)');
this.gradient2 = gradient2 = g.createLinearGradient(-radius, 0, 0, 0);
gradient2.addColorStop(0, 'hsla(' + hueStart + ', ' + 50 + '%, ' + 40 + '%, 1.0)');
gradient2.addColorStop(1, 'hsla(' + hueEnd + ', ' + 50 + '%, ' + 40 + '%, 0.1)');
}
g.globalCompositeOperation = 'destination-out'; //'destination-out';
g.fillStyle = 'hsla(0, 0%, 0%, 0.1)';
g.fillRect(0, 0, width, height);
g.globalCompositeOperation = 'lighter';
var i;
for (i = 2; i < 3; i++) {
g.beginPath();
g.arc(radius, radius, ((radius - 1) / 4) * (i + 1), 0, Math.PI * 2, false);
g.strokeStyle = 'hsla(' + (hueEnd - (i * (hueDiff / 4))) + ', ' + 50 + '%, ' + 40 + '%, 0.1)';
g.lineWidth = 2;
g.stroke();
};
g.beginPath();
g.save();
g.translate(radius, radius);
g.rotate(data.getClient('angle'));
g.arc(((radius - 1) / 4) * (2.5 + 1), 0, 4, 0, Math.PI * 2, false);
g.fillStyle = gradient;
g.fill();
g.restore();
g.beginPath();
g.save();
g.translate(radius, radius);
g.rotate(data.getClient('angle'));
g.arc(-((radius - 1) / 4) * (2.5 + 1), 0, 4, 0, Math.PI * 2, false);
g.fillStyle = gradient2;
g.fill();
g.restore();
ctx.scale(1 / view.getZoom(), 1 / view.getZoom());
ctx.drawImage(canvas, -width / 2, -height / 2);
stats.end();
性能对比
FlowLink
image.png
双轨迹
image.png
明显后者性能好于前者。
网友评论