Copyright 2011, jsr@malamute.dk, released under the WTFPL
This script produces a – scientifically broken – seismograph, using data from one of three events:
By the time of writing (March 2011), the two first are supported by Chrome and Mobile Safari, and the latter in Firefox.
Create any sort of HTML element – eg a div – and make sure it has width,
height, foreground and background color defined somewhere (inline or in a
style sheet). Now, add a script element within the container, loading
http://isthisanearthquake.com/seismograph.js.
That's it! Have a look at the source code in this sample:
If you add additional content within the container – besides the script
element – this will be shown as a fall-back when no Javascript available.
Wrap everything in a function, to avoid polluting the global namespace.
(function () {Use a dirty old trick to dump an anchor where the script is called.
document.write('<a id="itae-anchor" href="http://isthisanearthquake.com"></a>');Grab a reference to the DOM, and create additional elements.
var anchor = document.getElementById('itae-anchor'),
container = anchor.parentNode,
viewport = document.createElement('div');Make sure our elements are alone in the container. This will remove any default content.
while (container.hasChildNodes()) {
container.removeChild(container.firstChild);
}
container.appendChild(anchor);
container.appendChild(viewport);Put the anchor and the seismograph viewport on top of each other.
Let's use getComputedStyle() to figure out how this should look.
var style = window.getComputedStyle(container, null);
anchor.style.position = 'absolute';
anchor.style.width = viewport.style.width = style.width;
anchor.style.height = viewport.style.height = style.height;
anchor.style.zIndex = 1;
anchor.style.zIndex = 0;We are going to be painting on a canvas wider than our container. Tell the viewport to hide overflow, so that we can auto-scroll it.
viewport.style.overflow = 'hidden';The following might look scary, but it actually isn't that bad. It's all about defining some constants for later use.
var width = viewport.clientWidth,
height = viewport.clientHeight,
pan = Math.round(width / 200),
totalWidth = pan * 1000,
zero = height / 2,
refreshRate = 100,
threshold = 50;Ok – we will need a few variables as well.
var x, y = zero,
deflection = 0,
axesPrev = [],
canvas, ctx; var freshCanvas = function () {Create a new canvas, and make it pretty wide.
var newCanvas = document.createElement('canvas');
newCanvas.width = totalWidth;
newCanvas.height = height;Add it to our viewport, and scroll this all the way to the left. As we paint on the canvas, we will scroll the viewport rigtwards.
viewport.appendChild(newCanvas);
viewport.scrollLeft = 0;Prepare to paint on the canvas, using a 2D context.
ctx = newCanvas.getContext('2d');
ctx.strokeStyle = style.color;If an old canvas exists, copy the last screenfull of pixels over. This trick gives the illusion of an infinate scrolling canvas.
if (canvas) {
ctx.drawImage(canvas, width - x, 0);
viewport.removeChild(canvas);
}
canvas = newCanvas;
x = width;
}; var scrollCanvas = function() {
viewport.scrollLeft++;As we run out of space, get a fresh canvas.
if (viewport.scrollLeft >= totalWidth - width) {
freshCanvas();
}
}; var drawTheLine = function () {Move the pencil to where we left off, and put it to the canvas.
ctx.beginPath();
ctx.moveTo(x, y);Compute and move pencil to next location, stroking a line.
x += pan;
y = zero + (height * deflection / 25);
deflection = Math.random() * .2 - .1;
ctx.lineTo(x, y);
ctx.stroke();Each invocation of scollCanvas moves by one pixel.
Schedule enough invocations to animate until next refresh.
for (var i = 0; i < pan; i++) {
setTimeout(scrollCanvas, i * refreshRate / pan);
}
}; var tilt = function (axes) {We need to compare the current state with the previous state.
To do this, we need the axesPrev variable to be set.
if (axesPrev) {Depending on the type of event, any number of axis may exists. Find the one which has changed the most since last time.
for (var i = 0; i < axes.length; i++) {
var delta = axes[i] - axesPrev[i];
if (Math.abs(delta) > Math.abs(deflection)) {
deflection = delta;
}
}
}
axesPrev = axes;
};Grab the first canvas, and strike a flat line across it.
freshCanvas();
ctx.moveTo(0, y);
ctx.lineTo(x, y);
ctx.stroke();Hook up to the best available event. Use magic constants to keep results somewhat similar.
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(event) {
tilt([event.beta, event.gamma]);
}, true);
} else if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', function(event) {
tilt([event.acceleration.x * 2, event.acceleration.y * 2]);
}, true);
} else {
window.addEventListener('MozOrientation', function(orientation) {
tilt([orientation.x * 50, orientation.y * 50]);
}, true);
}Hook up a timer to draw new data on the seismograph.
setInterval(drawTheLine, refreshRate);
})();