Commit 713ea34c authored by Christopher S Barnett's avatar Christopher S Barnett
Browse files

- updated animation to throttle fps (was a big variation in speed

depending on number of migration arcs.
- updated animation to make arcs clearer. pulses only occur for zero
length arcs, arc width is smaller, circular markers added to beginning
and ends, animated migration arrow is sized depending on zoom level.
parent e8ffdb4b
This diff is collapsed.
......@@ -152,7 +152,7 @@
<div id="legend">
<svg transform="scale(1.3)" width="130" height="75">
<svg transform="scale(1.3)" width="190" height="75">
<pattern id="diagonalHatch" width="4" height="4" patternTransform="rotate(-45 0 0)"
patternUnits="userSpaceOnUse">
<line x1="0" y1="0" x2="12" y2="0" style="stroke:#01665e; stroke-width:4"/>
......@@ -164,7 +164,7 @@
<line x1="28" y1="40" x2="40" y2="40" class="buyer"/>
<text x="40" y="40" transform="translate(8,4)">Buyer</text>
<rect x="28" y="54" width="12" height="12" class="internal" fill="url(#diagonalHatch)"/>
<text x="40" y="60" transform="translate(8,4)">Internal Deal</text>
<text x="40" y="60" transform="translate(8,4)">Both / Internal Deal</text>
</svg>
</div>
......
......@@ -49,6 +49,7 @@
this.style = options.style;
this.color = options.color;
this.size = options.size;
this.zoom = options.zoom;
this.borderWidth = options.borderWidth;
this.borderColor = options.borderColor;
};
......@@ -64,13 +65,15 @@
// 目前先只支持圆
context.beginPath();
if (this.style === 'circle') {
context.arc(0, 0, this.size, 0, Math.PI * 2, false);
var adjSize = this.size * this.zoom / 2;
context.arc(0, 0, adjSize, 0, Math.PI * 2, false);
} else if (this.style === 'arrow') {
context.moveTo(-this.size, -this.size);
context.lineTo(this.size, 0);
context.lineTo(-this.size, this.size);
context.lineTo(-this.size / 4, 0);
context.lineTo(-this.size, -this.size);
var adjSize = this.size * this.zoom / 2;
context.moveTo(-adjSize, -adjSize);
context.lineTo(adjSize, 0);
context.lineTo(-adjSize, adjSize);
context.lineTo(-adjSize / 4, 0);
context.lineTo(-adjSize, -adjSize);
}
context.closePath();
context.stroke();
......@@ -91,7 +94,7 @@
var L = Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));
var m = (startX + endX) / 2; // 横轴中点
var n = (startY + endY) / 2; // 纵轴中点
var factor = 1.5;
var factor = 1.0;
var centerX = (startY - endY) * factor + m;
var centerY = (endX - startX) * factor + n;
......@@ -122,10 +125,9 @@
A.prototype.draw = function (context) {
context.save();
context.lineWidth = this.lineWidth;
context.strokeStyle = this.strokeStyle;
context.shadowColor = this.strokeStyle;
context.shadowBlur = this.shadowBlur || 2;
context.strokeStyle = 'rgb(54,144,192, 0.5)';
context.shadowColor = context.strokeStyle;
context.shadowBlur = this.shadowBlur || 1;
context.beginPath();
context.arc(this.centerX, this.centerY, this.radius, this.startAngle, this.endAngle, false);
context.stroke();
......@@ -136,8 +138,8 @@
if (this.label) {
context.font = this.label;
if (this.startLabel) {
var x = this.startX - 15
var y = this.startY + 5
var x = this.startX - 15;
var y = this.startY + 5;
context.fillText(this.startLabel, x, y);
}
if (this.endLabel) {
......@@ -163,7 +165,7 @@
this.r = 0;
this.factor = 2 / options.radius;
this.defaultFactor = 2 / options.radius;
};
}
P.prototype.draw = function (context) {
// var vr = (this.maxRadius - this.r) * this.factor;
......@@ -176,8 +178,8 @@
var strokeColor = this.color;
strokeColor = utils.calculateColor(strokeColor, 1 - this.r / this.maxRadius);
context.strokeStyle = strokeColor;
context.shadowBlur = this.shadowBlur;
context.shadowColor = strokeColor;
//context.shadowBlur = this.shadowBlur;
//context.shadowColor = strokeColor;
context.lineWidth = this.lineWidth;
context.beginPath();
context.arc(0, 0, this.r, 0, Math.PI * 2, false);
......@@ -187,7 +189,7 @@
if (Math.abs(this.maxRadius - this.r) < 0.8) {
this.r = 0;
}
}
};
return P;
})();
......@@ -201,9 +203,10 @@
//两点之间的圆有多个,通过两点及半径便可以定出两个圆,根据需要选取其中一个圆
var L = Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));
var m = (startX + endX) / 2; // 横轴中点
var n = (startY + endY) / 2; // 纵轴中点
var factor = 1.5;
var factor = 1.0;
var centerX = (startY - endY) * factor + m;
var centerY = (endX - startX) * factor + n;
......@@ -230,8 +233,12 @@
this.radius = radius;
this.lineWidth = options.width || 1;
this.strokeStyle = options.color || '#fff';
// TODO: set this dynamically based on distance (L)
this.defaultFactor = 0.0035; //1 / Math.pow(L, 1.5); //Math.min(2 / this.radius, 0.003);
var zoom = options.zoom || 1;
if (L > 0) {
this.defaultFactor = 0.005; //2.0 / L;
} else {
this.defaultFactor = 0.0035;
}
//console.log(this.defaultFactor);
this.factor = this.defaultFactor;
this.deltaAngle = (80 / Math.min(this.radius, 400)) / this.tailPointsCount;
......@@ -246,7 +253,8 @@
rotation: 50 * Math.PI / 180,
style: 'arrow',
color: 'rgb(255, 255, 255)',
size: 3,
size: 2,
zoom: zoom,
borderWidth: 0,
borderColor: this.strokeStyle
});
......@@ -275,6 +283,7 @@
};
S.prototype.draw = function (context) {
var endAngle = this.endAngle;
// 匀速
var angle = this.trailAngle + this.factor;
......@@ -291,7 +300,7 @@
var count = this.tailPointsCount;
for (var i = 0; i < count; i++) {
var arcColor = utils.calculateColor(this.strokeStyle, 0.3 - 0.3 / count * i);
var tailLineWidth = 5;
var tailLineWidth = 2;
if (this.trailAngle - this.deltaAngle * i > this.startAngle) {
this.drawArc(context, arcColor,
tailLineWidth - tailLineWidth / count * i,
......@@ -373,7 +382,10 @@
/*
* 更新数据
*/
M.prototype.updateData = function (data) {
M.prototype.updateData = function (data, zoom) {
if (!zoom) {
zoom = 1;
}
if (!data || data.length === 0) {
return;
}
......@@ -400,15 +412,27 @@
width: this.style.arc.width,
color: element.color
});
var marker = new Marker({
var startmarker = new Marker({
x: element.from[0],
y: element.from[1],
rotation: arc.endAngle + Math.PI / 2,
style: 'circle',
color: element.color,
size: 1,
borderWidth: 1,
borderColor: '#000',
zoom: zoom
});
var endmarker = new Marker({
x: element.to[0],
y: element.to[1],
rotation: arc.endAngle + Math.PI / 2,
style: 'arrow',
style: 'circle',
color: element.color,
size: 4,
borderWidth: 0,
borderColor: element.color
size: 2,
borderWidth: 1,
borderColor: '#000',
zoom: zoom
});
var spark = new Spark({
......@@ -416,25 +440,28 @@
startY: element.from[1],
endX: element.to[0],
endY: element.to[1],
width: 15,
color: element.color
width: 5,
color: element.color,
zoom: zoom
});
this.store.arcs.push(arc);
this.store.markers.push(marker);
this.store.markers.push(startmarker);
this.store.markers.push(endmarker);
this.store.sparks.push(spark);
}
var pulse = new Pulse({
x: element.to[0],
y: element.to[1],
radius: this.style.pulse.radius,
color: element.color,
borderWidth: this.style.pulse.borderWidth
});
} else {
// CB: only show pulses for single point
var pulse = new Pulse({
x: element.to[0],
y: element.to[1],
radius: this.style.pulse.radius,
color: element.color,
borderWidth: this.style.pulse.borderWidth
});
this.store.pulses.push(pulse);
this.store.pulses.push(pulse);
}
}, this);
}
......@@ -443,20 +470,50 @@
*/
M.prototype.start = function (canvas) {
var that = this;
var then = Date.now();
var startTime = then;
var elapsed;
var frameCount = 0;
var throttledfps = 24;
var fpsInterval = 1000 / throttledfps;
if (!this.started) {
(function drawFrame() {
that.requestAnimationId = window.requestAnimationFrame(drawFrame, canvas);
var now = Date.now();
elapsed = now - then;
if (that.playAnimation) {
canvas.width += 1;
canvas.width -= 1;
for (var p in that.store) {
var shapes = that.store[p];
for (var i = 0, len = shapes.length; i < len; i++) {
shapes[i].draw(that.context);
if (elapsed > fpsInterval) {
// Get ready for next frame by setting then=now, but...
// Also, adjust for fpsInterval not being multiple of 16.67
then = now - (elapsed % fpsInterval);
// draw stuff here
canvas.width = canvas.width;
//canvas.width -= 1;
function drawShapes(shapes) {
for (var i = 0, len = shapes.length; i < len; i++) {
shapes[i].draw(that.context);
}
}
drawShapes(that.store.arcs);
drawShapes(that.store.markers);
drawShapes(that.store.pulses);
drawShapes(that.store.sparks);
/* var sinceStart = now - startTime;
var currentFps = Math.round(1000 / (sinceStart / ++frameCount) * 100) / 100;
console.log(currentFps - throttledfps);*/
}
}
})();
this.started = true;
......@@ -587,7 +644,7 @@
});
this._map.on('zoomend', function () {
if (that._show) {
that.container.style.display = ''
that.container.style.display = '';
that._draw();
}
});
......@@ -598,7 +655,7 @@
this._resize();
this._transform();
var data = this._convertData();
this.migration.updateData(data);
this.migration.updateData(data, this._map.getZoom());
this.migration.start(this.canvas);
}
},
......@@ -615,7 +672,7 @@
this._transform();
var data = this._convertData();
this.migration.updateData(data);
this.migration.updateData(data, this._map.getZoom());
this.migration.start(this.canvas);
}
},
......
......@@ -539,6 +539,7 @@ ConnectionMap = function () {
return country;
},
/**
* load 'deal' collection, add the migration (arrows) layer, initialize selection, set sources and targets
* @returns {*} promise returned from getJSON
......@@ -554,23 +555,34 @@ ConnectionMap = function () {
//self.connections = _.groupBy(data, "deal_name");
self.deals = data.data;
self.migrationLayer = new L.migrationLayer({
map: self.map,
data: []
});
self.migrationLayer.addTo(self.map);
self.createMigrationLayer();
self.selectDeals(selType, selValue, true);
self.renderSourcesAndTargets();
});
},
sources: {},
targets: {},
createMigrationLayer: function () {
this.migrationLayer = new L.migrationLayer({
map: this.map,
data: []
});
this.migrationLayer.addTo(this.map);
},
renewMigrationLayer: function (data) {
this.migrationLayer.migration.clear();
this.migrationLayer.setData(data);
},
/**
* copy country geometry.
* @param ids country ids from geojson
......@@ -777,7 +789,7 @@ ConnectionMap = function () {
*/
clearLinks: function () {
this.resetHighlight();
this.migrationLayer.setData([]);
this.renewMigrationLayer([]);
this.migrationLayer.hide();
},
......@@ -902,10 +914,11 @@ ConnectionMap = function () {
}
});
self.migrationLayer.setData(migrations);
//self.migrationLayer.setData(migrations);
self.renewMigrationLayer(migrations);
// currently, we only want to show connections for 1 deal at a time
if (migrations.length > 0 && self.filtered_deals.length === 1) {
if (migrations.length > 0) { //} && self.filtered_deals.length === 1) {
self.migrationLayer.show();
} else {
self.migrationLayer.hide();
......@@ -919,6 +932,7 @@ $(document).ready(function () {
var selType = 'by-deal';
var selValue = '';
// support query via url hash fragment
if (window.location.hash) {
// Fragment exists
var fragmentArr = window.location.hash.substr(1).split('=');
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment