Glitching out a <canvas>
by converting it to JPEG and trashing some random bytes.
See also: Video glitching
Glitching out a <canvas>
by converting it to JPEG and trashing some random bytes.
See also: Video glitching
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<body> | |
<canvas width="960" height="500"></canvas> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script> | |
<script src="https://d3js.org/topojson.v2.min.js"></script> | |
<script> | |
var canvas = document.querySelector("canvas"), | |
context = canvas.getContext("2d"), | |
delay = d3.randomExponential(1 / 900), | |
duration = d3.randomExponential(1 / 175), | |
glitched = false, | |
width = 960, | |
height = 500; | |
var projection = d3.geoOrthographic() | |
.scale(195) | |
.translate([width / 2, height / 2]) | |
.precision(.1); | |
var path = d3.geoPath() | |
.projection(projection) | |
.context(context); | |
d3.json("/mbostock/raw/4090846/world-110m.json",function(err,world){ | |
var land = topojson.feature(world,world.objects.land), | |
mesh = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }); | |
d3.timer(function(t){ | |
if (glitched) return true; | |
projection.rotate([360 * (t % 10000 / 10000)]); | |
context.lineWidth = 1; | |
context.fillStyle = "#fff"; | |
context.fillRect(0, 0, width, height); | |
context.strokeStyle = "#222"; | |
context.beginPath(); | |
path({type: "Sphere"}); | |
context.stroke(); | |
context.fillStyle = "#222"; | |
context.beginPath(); | |
path(land); | |
context.fill(); | |
context.strokeStyle = "#fff"; | |
context.beginPath(); | |
path(mesh); | |
context.stroke(); | |
}); | |
d3.timeout(glitch, delay()); | |
}); | |
function glitch() { | |
var bytes = toByteArray(canvas.toDataURL("image/jpeg").substring(23)), | |
density = glitchDensity(), | |
glitchedBytes = fromByteArray(glitchBytes(bytes, density)), | |
img = new Image(); | |
img.onload = function(){ | |
context.drawImage(img, 0, 0); | |
glitched = true; | |
d3.timeout(function(){ | |
glitched = false; | |
d3.timeout(glitch, Math.min(3000, delay())); | |
}, duration()); | |
}; | |
img.src = "data:image/jpeg;base64," + glitchedBytes; | |
} | |
function glitchDensity() { | |
return [2, 3, 5, 10, 25, 100][~~(Math.random() * 6)]; | |
} | |
function glitchBytes( byteArray, density ) { | |
var generator = d3.randomExponential(density / byteArray.length), | |
i = 611 + ~~generator(), | |
max = byteArray.length - 4, | |
val = ~~(Math.random() * 256); | |
while (i < max) { | |
byteArray[i] = val; | |
i += ~~generator(); | |
} | |
return byteArray; | |
} | |
function toByteArray(str) { | |
var byteString = atob(str), | |
len = byteString.length, | |
byteArray = new Uint8Array(len); | |
for (var i = 0; i < len; i++) { | |
byteArray[i] = byteString.charCodeAt(i); | |
} | |
return byteArray; | |
} | |
function fromByteArray(arr) { | |
return btoa(String.fromCharCode.apply(null, arr)); | |
} | |
</script> |