Permalink
Browse files

Port html5rocks.com SSE example to cramp

  • Loading branch information...
lifo committed Feb 13, 2011
1 parent 56dea0b commit 349d4b3a1260cb0ed5c297c461dfcda7fd823ab7
Showing with 615 additions and 0 deletions.
  1. +35 −0 examples/sse/HTML5ROCK_LICENSE
  2. +318 −0 examples/sse/public/coolclock.js
  3. +237 −0 examples/sse/public/demo.html
  4. +25 −0 examples/sse/server.rb
@@ -0,0 +1,35 @@
+This project includes the html5lib library:
+http://code.google.com/p/html5lib/
+
+Which is licensed under the following license:
+Copyright (c) 2006-2008 The Authors
+
+Contributors:
+James Graham - jg307@cam.ac.uk
+Anne van Kesteren - annevankesteren@gmail.com
+Lachlan Hunt - lachlan.hunt@lachy.id.au
+Matt McDonald - kanashii@kanashii.ca
+Sam Ruby - rubys@intertwingly.net
+Ian Hickson (Google) - ian@hixie.ch
+Thomas Broyer - t.broyer@ltgt.net
+Jacques Distler - distler@golem.ph.utexas.edu
+Henri Sivonen - hsivonen@iki.fi
+The Mozilla Foundation (contributions from Henri Sivonen since 2008)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
@@ -0,0 +1,318 @@
+/**
+ * CoolClock 2.1.4
+ * Copyright 2010, Simon Baird
+ * Released under the BSD License.
+ *
+ * Display an analog clock using canvas.
+ * http://randomibis.com/coolclock/
+ *
+ */
+
+// Constructor for CoolClock objects
+window.CoolClock = function(options) {
+ return this.init(options);
+}
+
+// Config contains some defaults, and clock skins
+CoolClock.config = {
+ tickDelay: 1000,
+ longTickDelay: 15000,
+ defaultRadius: 85,
+ renderRadius: 100,
+ defaultSkin: "swissRail",
+ // Should be in skin probably...
+ // (TODO: allow skinning of digital display)
+ showSecs: true,
+ showAmPm: true,
+
+ skins: {
+ // There are more skins in moreskins.js
+ // Try making your own skin by copy/pasting one of these and tweaking it
+ swissRail: {
+ outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 },
+ smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
+ largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
+ hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
+ minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
+ secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
+ secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
+ },
+ chunkySwiss: {
+ outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 },
+ smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
+ largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
+ hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
+ minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
+ secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
+ secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
+ },
+ chunkySwissOnBlack: {
+ outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 },
+ smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
+ largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
+ hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
+ minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
+ secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
+ secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
+ }
+
+ },
+
+ // Test for IE so we can nurse excanvas in a couple of places
+ isIE: !!document.all,
+
+ // Will store (a reference to) each clock here, indexed by the id of the canvas element
+ clockTracker: {},
+
+ // For giving a unique id to coolclock canvases with no id
+ noIdCount: 0
+};
+
+// Define the CoolClock object's methods
+CoolClock.prototype = {
+
+ // Initialise using the parameters parsed from the colon delimited class
+ init: function(options) {
+ // Parse and store the options
+ this.canvasId = options.canvasId;
+ this.skinId = options.skinId || CoolClock.config.defaultSkin;
+ this.displayRadius = options.displayRadius || CoolClock.config.defaultRadius;
+ this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true;
+ this.gmtOffset = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;
+ this.showDigital = typeof options.showDigital == "boolean" ? options.showDigital : false;
+ this.logClock = typeof options.logClock == "boolean" ? options.logClock : false;
+ this.logClockRev = typeof options.logClock == "boolean" ? options.logClockRev : false;
+
+ this.tickDelay = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ];
+
+ // Get the canvas element
+ this.canvas = document.getElementById(this.canvasId);
+
+ // Make the canvas the requested size. It's always square.
+ this.canvas.setAttribute("width",this.displayRadius*2);
+ this.canvas.setAttribute("height",this.displayRadius*2);
+ this.canvas.style.width = this.displayRadius*2 + "px";
+ this.canvas.style.height = this.displayRadius*2 + "px";
+
+ // Explain me please...?
+ this.renderRadius = CoolClock.config.renderRadius;
+ this.scale = this.displayRadius / this.renderRadius;
+
+ // Initialise canvas context
+ this.ctx = this.canvas.getContext("2d");
+ this.ctx.scale(this.scale,this.scale);
+
+ // Keep track of this object
+ CoolClock.config.clockTracker[this.canvasId] = this;
+
+ // Start the clock going
+ //this.tick();
+
+ return this;
+ },
+
+ // Draw a circle at point x,y with params as defined in skin
+ fullCircleAt: function(x,y,skin) {
+ this.ctx.save();
+ this.ctx.globalAlpha = skin.alpha;
+ this.ctx.lineWidth = skin.lineWidth;
+
+ if (!CoolClock.config.isIE) {
+ this.ctx.beginPath();
+ }
+
+ if (CoolClock.config.isIE) {
+ // excanvas doesn't scale line width so we will do it here
+ this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
+ }
+
+ this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);
+
+ if (CoolClock.config.isIE) {
+ // excanvas doesn't close the circle so let's fill in the tiny gap
+ this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);
+ }
+
+ if (skin.fillColor) {
+ this.ctx.fillStyle = skin.fillColor
+ this.ctx.fill();
+ }
+ else {
+ // XXX why not stroke and fill
+ this.ctx.strokeStyle = skin.color;
+ this.ctx.stroke();
+ }
+ this.ctx.restore();
+ },
+
+ // Draw some text centered vertically and horizontally
+ drawTextAt: function(theText,x,y) {
+ this.ctx.save();
+ this.ctx.font = '15px sans-serif';
+ var tSize = this.ctx.measureText(theText);
+ if (!tSize.height) tSize.height = 15; // no height in firefox.. :(
+ this.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2);
+ this.ctx.restore();
+ },
+
+ lpad2: function(num) {
+ return (num < 10 ? '0' : '') + num;
+ },
+
+ tickAngle: function(second) {
+ // Log algorithm by David Bradshaw
+ var tweak = 3; // If it's lower the one second mark looks wrong (?)
+ if (this.logClock) {
+ return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));
+ }
+ else if (this.logClockRev) {
+ // Flip the seconds then flip the angle (trickiness)
+ second = (60 - second) % 60;
+ return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));
+ }
+ else {
+ return second/60.0;
+ }
+ },
+
+ timeText: function(hour,min,sec) {
+ var c = CoolClock.config;
+ return '' +
+ (c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +
+ this.lpad2(min) +
+ (c.showSecs ? ':' + this.lpad2(sec) : '') +
+ (c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '')
+ ;
+ },
+
+ // Draw a radial line by rotating then drawing a straight line
+ // Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)
+ radialLineAtAngle: function(angleFraction,skin) {
+ this.ctx.save();
+ this.ctx.translate(this.renderRadius,this.renderRadius);
+ this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));
+ this.ctx.globalAlpha = skin.alpha;
+ this.ctx.strokeStyle = skin.color;
+ this.ctx.lineWidth = skin.lineWidth;
+
+ if (CoolClock.config.isIE)
+ // excanvas doesn't scale line width so we will do it here
+ this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
+
+ if (skin.radius) {
+ this.fullCircleAt(skin.startAt,0,skin)
+ }
+ else {
+ this.ctx.beginPath();
+ this.ctx.moveTo(skin.startAt,0)
+ this.ctx.lineTo(skin.endAt,0);
+ this.ctx.stroke();
+ }
+ this.ctx.restore();
+ },
+
+ render: function(hour,min,sec) {
+ // Get the skin
+ var skin = CoolClock.config.skins[this.skinId];
+ if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];
+
+ // Clear
+ this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);
+
+ // Draw the outer edge of the clock
+ if (skin.outerBorder)
+ this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);
+
+ // Draw the tick marks. Every 5th one is a big one
+ for (var i=0;i<60;i++) {
+ (i%5) && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);
+ !(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);
+ }
+
+ // Write the time
+ if (this.showDigital) {
+ this.drawTextAt(
+ this.timeText(hour,min,sec),
+ this.renderRadius,
+ this.renderRadius+this.renderRadius/2
+ );
+ }
+
+ // Draw the hands
+ if (skin.hourHand)
+ this.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand);
+
+ if (skin.minuteHand)
+ this.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand);
+
+ if (this.showSecondHand && skin.secondHand)
+ this.radialLineAtAngle(this.tickAngle(sec),skin.secondHand);
+
+ // Second hand decoration doesn't render right in IE so lets turn it off
+ if (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration)
+ this.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration);
+ },
+
+ // Check the time and display the clock
+ refreshDisplay: function() {
+ var now = new Date();
+ if (this.gmtOffset != null) {
+ // Use GMT + gmtOffset
+ var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));
+ this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds());
+ }
+ else {
+ // Use local time
+ this.render(now.getHours(),now.getMinutes(),now.getSeconds());
+ }
+ },
+
+ // Set timeout to trigger a tick in the future
+ nextTick: function() {
+ setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay);
+ },
+
+ // Check the canvas element hasn't been removed
+ stillHere: function() {
+ return document.getElementById(this.canvasId) != null;
+ },
+
+ // Main tick handler. Refresh the clock then setup the next tick
+ tick: function() {
+ if (this.stillHere()) {
+ this.refreshDisplay()
+ this.nextTick();
+ }
+ }
+};
+
+// Find all canvas elements that have the CoolClock class and turns them into clocks
+CoolClock.findAndCreateClocks = function() {
+ // (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)
+ var canvases = document.getElementsByTagName("canvas");
+ for (var i=0;i<canvases.length;i++) {
+ // Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
+ var fields = canvases[i].className.split(" ")[0].split(":");
+ if (fields[0] == "CoolClock") {
+ if (!canvases[i].id) {
+ // If there's no id on this canvas element then give it one
+ canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
+ }
+ // Create a clock object for this element
+ return new CoolClock({
+ canvasId: canvases[i].id,
+ skinId: fields[1],
+ displayRadius: fields[2],
+ showSecondHand: fields[3]!='noSeconds',
+ gmtOffset: fields[4],
+ showDigital: fields[5]=='showDigital',
+ logClock: fields[6]=='logClock',
+ logClockRev: fields[6]=='logClockRev'
+ });
+ }
+ }
+};
+
+// If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
+// If you do have jQuery and it's loaded already then we can do it right now
+if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);
Oops, something went wrong.

0 comments on commit 349d4b3

Please sign in to comment.