Skip to content

Instantly share code, notes, and snippets.

@cool-Blue
Last active September 10, 2015 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cool-Blue/23ca2f006b720c784fc2 to your computer and use it in GitHub Desktop.
Save cool-Blue/23ca2f006b720c784fc2 to your computer and use it in GitHub Desktop.
SVG speed test
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
svg {
border: 1px solid rgba(0,0,0,0.5);
}
#results, #container {
display: inline-block;
margin: 15px;
}
p {
margin: 15px;
}
td {
border: 1px solid #bbb;
text-align: right;
}
.header {
font-weight: bold;
}
</style>
</head>
<body>
<p id="user-agent"></p>
<div id="container"></div>
<table id="results">
<tr class="header">
<td>Circles</td>
<td>FPS</td>
<td>repaint [ms]</td>
</tr>
</table>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.1.2/tinycolor.min.js"></script>
<script src="https://gitcdn.xyz/repo/cool-Blue/d3-lib/master/filters/shadow.js"></script>
<div id="log1"></div>
<div id="log2"></div>
<script>
$(function (){
/* global requestAnimationFrame, $, PIXI, canvg */
window.requestAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
return window.setTimeout(callback, 1000/60);
};
})();
var tests = [250, 500, 750, 1000, 2000, 3000, 10000, 20000];
var refTest = tests[0];
var maxRadius = 30,
maxX = 680,
maxY = 400;
function addRecord(count) {
var results = d3.select("#results")
.append("tr").selectAll("td").data([d3.format(",f")(count),"",""])
results.enter().append("td")
.text(function(d){return d});
return function updateResults(time, steps) {
var repaint = time / steps;
results.datum([count, (1000 / repaint).toFixed(2), repaint.toFixed(2)])
.text(function(d, i){return this.textContent || d[i]});
}
}
// set up svg
var svg = d3.select("#container").append("svg")
.attr({width: maxX, height: maxY})
.append("g"),
g = svg.append("g"),
bubble = Bubble(svg),
x = d3.scale.linear()
.range([0, maxX])
.domain([maxX * 0.1, maxX * 0.9]),
y = d3.scale.linear()
.range([0, maxY])
.domain([maxY * 0.1, maxY * 0.9]),
constraint = [
[x.invert(0), y.invert(0)],
[x.invert(maxX), y.invert(0)],
[x.invert(maxX), y.invert(maxY)],
[x.invert(0), y.invert(maxY)]
];
function test() {
var count,
maxSteps = 100,
steps = 0,
startTime,
circle,
v = 20;
if (tests.length > 0) {
count = tests.shift();
} else {
return;
}
var r = Math.pow(1.1, -(count - refTest) / refTest) * (1 - 1/10) + 1/10,
updateResults = addRecord(count),
circles = g.selectAll("circle").data(d3.range(count).map( function(d) {
var species = Math.random(), rMax = maxRadius * r;
return {
x: x.invert(rMax + (maxX - rMax*2) * Math.random()),
y: y.invert(rMax + (maxY - rMax*2) * Math.random()),
r : rMax * (species + 0.25),
color: Math.round(species * 19),
vx: (Math.random() - 0.5) * v,
vy: (Math.random() - 0.5) * v,
index: d
};
}));
circles.exit().remove();
circles.enter().append("circle")
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut)
.call(d3.behavior.drag()
.on("dragstart", onDragStart)
.on("drag", onDragMove)
.on("dragend", onDragEnd));
circles.attr("r", function(d){return d.r})
.attr("transform", function(d){return "translate(" + [d.x, d.y] + ")"})
.call(bubble.call);
svg.selectAll("path").data([constraint])
.enter().append("path").attr("d", function(d){
return d3.svg.line()(d) + "Z";
})
.style({fill: "none", stroke: "black", opacity: 0.3});
// Start animation.
startTime = new Date().getTime();
requestAnimationFrame(step);
function step() {
var time;
circles.attr("transform", function(c){
if(!c.fixed) {
if(x(c.x) >= (maxX - c.r) || x(c.x) <= c.r) c.vx *= -1;
if(y(c.y) >= (maxY - c.r) || y(c.y) <= c.r) c.vy *= -1;
c.x += c.vx;
c.y += c.vy;
}
return "translate(" + [c.x, c.y] + ")";
});
if (steps < maxSteps) {
steps++;
requestAnimationFrame(step);
} else {
time = new Date().getTime() - startTime;
updateResults(time, maxSteps);
test();
}
}
function onMouseOver(d) {
d.fixed |= 4;
console.log([myName(arguments), this.index].join(": "))
d.x -= d.vx;
d.y -= d.vy;
d3.select(this).moveToFront();
}
function onMouseOut(d) {
console.log(["\t", myName(arguments), this.index].join(": "))
d.fixed &= ~4;
}
function onDragStart(d) {
console.log([myName(arguments), this.index].join(": "))
// store a reference to the data
// the reason for this is because of multitouch
// we want to track the movement of this particular touch
d3.select(this).style("opacity", 0.5);
d.fixed |= 2;
}
function onDragEnd(d) {
console.log(["\t", myName(arguments), this.index].join(": "))
d3.select(this).style("opacity", 1);
d.fixed &= ~6;
}
function onDragMove(d) {
if (d.fixed & 2) {
console.log([myName(arguments), this.index].join(": "))
var newPosition = d3.mouse(svg.node()) || d3.touch(svg.node());
d.x = newPosition[0];
d.y = newPosition[1];
}
}
}
$(function () {
$("#user-agent").text(navigator.userAgent);
test();
});
function Bubble(svg) {
var colors = d3.range(20).map(d3.scale.category10()).map(function(d) {
return filters.sphere(svg, d, 1)
});
return {
call: function(selection) {
selection.style("fill", function(d) {
return colors[d.color]
})
},
map : function(d, i, data) {
d.fill = colors[~~(Math.random() * 20)];
},
fill: function(d) {
return d.fill
}
}
}
function myName(args) {
return /function\s+(\w*)\(/.exec(args.callee)[1];
}
d3.selection.prototype.moveToFront = function() {
return this.each(function() {
this.parentNode.appendChild(this);
});
}
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment