Giraffe.js - HTML5 Canvas Graphics Library Documentation

Comprehensive documentation for the OpenForum Giraffe.js HTML5 canvas graphics library - a Javascript library for building animated interactive graphics with JSON schema support.

Overview

Giraffe.js is a lightweight HTML5 canvas graphics library designed for creating animated and interactive graphics applications. Built by Nik Cross, it provides an object-oriented approach to canvas programming with support for graphics primitives, composites, animations, user interaction, and JSON schema-based scene definition.

Core Architecture

Canvas Management

The library centers around the `Canvas` class, which represents an HTML5 canvas element and manages all graphics objects drawn on it. // Create a canvas instance var myCanvas = new Canvas("canvasElementId"); // Add graphics objects myCanvas.add(new Circle(100, 100, 50)); myCanvas.add(new Rectangle(200, 200, 100, 75)); // Repaint the canvas myCanvas.repaint();

Graphics Objects Hierarchy

All drawable objects inherit from the `GraphicsObject` base class, providing consistent behavior for positioning, styling, interaction, and animation.

JSON Schema Support

Giraffe.js supports defining graphics scenes using JSON schemas, allowing for data-driven graphics creation and easy serialization/deserialization of complex scenes. For the complete JSON schema definition, see the GiraffeJSSchema page.

JSON Scene Definition

var sceneData = { "canvas": { "id": "myCanvas", "width": 800, "height": 600, "backgroundColor": "#f0f0f0" }, "objects": [ { "type": "Circle", "id": "ball1", "x": 100, "y": 100, "radius": 30, "fillColor": "red", "color": "darkred", "animation": { "type": "bounce", "velocityX": 3, "velocityY": 2 } }, { "type": "Rectangle", "id": "paddle", "x": 350, "y": 550, "width": 100, "height": 20, "fillColor": "brown", "draggable": true }, { "type": "Text", "id": "score", "x": 10, "y": 30, "text": "Score: 0", "fontSize": 24, "font": "Arial", "color": "black" } ] }

JSON Schema Loader

function loadSceneFromJSON(sceneData, canvas) { var objects = {}; // Process each object in the scene sceneData.objects.forEach(function(objData) { var obj = createObjectFromJSON(objData); if (obj) { objects[objData.id] = obj; canvas.add(obj); } }); return objects; } function createObjectFromJSON(objData) { var obj = null; switch(objData.type) { case "Circle": obj = new Circle(objData.x, objData.y, objData.radius); break; case "Rectangle": obj = new Rectangle(objData.x, objData.y, objData.width, objData.height); break; case "Text": obj = new Text(objData.x, objData.y, objData.text, objData.fontSize, objData.font); break; // Add more types as needed } if (obj) { // Apply common properties if (objData.fillColor) obj.setFillColor(objData.fillColor); if (objData.color) obj.setColor(objData.color); if (objData.visible !== undefined) obj.visible = objData.visible; if (objData.rotation) obj.setRotation(objData.rotation); // Apply animation if specified if (objData.animation) { applyAnimation(obj, objData.animation); } // Apply interactivity if (objData.draggable) { canvas.makeDraggable(obj); } } return obj; }

JSON Export/Serialization

function exportSceneToJSON(canvas) { var sceneData = { canvas: { width: canvas.width, height: canvas.height }, objects: [] }; canvas.graphicsObjects.forEach(function(obj, index) { var objData = serializeObject(obj, "object_" + index); sceneData.objects.push(objData); }); return sceneData; } function serializeObject(obj) { var data = { x: obj.x, y: obj.y, color: obj.color, fillColor: obj.fillColor, visible: obj.visible, rotation: obj.rotation }; // Type-specific serialization if (obj instanceof Circle) { data.type = "Circle"; data.radius = obj.radius; } else if (obj instanceof Rectangle) { data.type = "Rectangle"; data.width = obj.width; data.height = obj.height; } else if (obj instanceof Text) { data.type = "Text"; data.text = obj.text; data.fontSize = obj.textSize; data.font = obj.font; } return data; }

Core Classes

Canvas

The main container for all graphics operations.

GraphicsObject (Base Class)

The foundation class for all drawable objects.

Graphics Primitives

Circle

Draws circular shapes with customizable radius. var rect = new Rectangle(50, 50, 200, 100) .setColor("red") .setFillColor("pink"); canvas.add(rect); var arc = new Arc(100, 100, 0, 90, 50) .setClosed() .setFillColor("yellow"); canvas.add(arc); var triangle = new Polygon(100, 100) .addPoint(0, -50) .addPoint(-50, 50) .addPoint(50, 50) .setFillColor("green"); canvas.add(triangle); var pixelCanvas = new PixelCanvas(0, 0, 100, 100); for (var x = 0; x < 100; x++) { for (var y = 0; y < 100; y++) { pixelCanvas.setPixel(x, y, x * 2.55, y * 2.55, 128, 255); } } canvas.add(pixelCanvas); var group = new Composite(200, 200, 0); group.add(new Circle(0, 0, 30).setFillColor("red")); group.add(new Circle(20, 0, 20).setFillColor("blue")); group.add(new Text(0, 50, "Group", 16, "Arial")); canvas.add(group); // Handle clicks on the entire group group.onClick = function(x, y) { alert("Clicked on composite!"); };

Helper Functions

// Get element position on page function getPosition(element) { // Returns [x, y] array of element position }

Complete Example Applications

Basic Interactive Scene with JSON

<!DOCTYPE html> <html> <head> <title>Giraffe.js JSON Demo</title> <script src="giraffe.js"></script> </head> <body> <canvas id="gameCanvas" width="800" height="600"></canvas> <script> var sceneJSON = `{ "canvas": { "width": 800, "height": 600, "backgroundColor": "#e6f3ff" }, "objects": [ { "type": "Circle", "id": "ball", "x": 100, "y": 100, "radius": 25, "fillColor": "red", "color": "darkred", "animation": { "type": "bounce", "velocityX": 4, "velocityY": 3, "bounceEdges": true } }, { "type": "RoundedRectangle", "id": "paddle", "x": 350, "y": 550, "width": 100, "height": 20, "cornerRadius": 10, "fillColor": "brown", "color": "black", "draggable": true }, { "type": "Text", "id": "title", "x": 10, "y": 30, "text": "Giraffe.js JSON Demo", "fontSize": 24, "font": "Arial", "color": "black" }, { "type": "Rectangle", "id": "button", "x": 650, "y": 20, "width": 100, "height": 40, "fillColor": "lightblue", "color": "blue", "interactive": { "onClick": { "action": "changeColor", "color": "yellow", "duration": 500 }, "onMouseOver": { "action": "changeColor", "color": "lightgreen" }, "onMouseOut": { "action": "changeColor", "color": "lightblue" } } } ] }`; // Create canvas and load scene var canvas = new Canvas("gameCanvas"); var loader = new GiraffeJSONLoader(); Giraffe.Interactive.setInteractive(canvas); Giraffe.setAnimated(canvas); var objects = loader.loadScene(sceneJSON, canvas); canvas.startAnimation(60, 10000, true); </script> </body> </html>

Game Example with JSON Configuration

var gameSceneJSON = `{ "canvas": { "width": 800, "height": 600, "backgroundColor": "#001122" }, "objects": [ { "type": "Composite", "id": "ship", "x": 400, "y": 500, "parts": [ { "type": "Polygon", "x": 0, "y": 0, "points": [[0, -20], [-15, 15], [0, 10], [15, 15]], "fillColor": "white", "closed": true } ], "interactive": { "onKeyPress": { "left": {"action": "move", "direction": "left", "speed": 5}, "right": {"action": "move", "direction": "right", "speed": 5}, "space": {"action": "fire"} } } }, { "type": "Circle", "id": "enemy1", "x": 100, "y": 50, "radius": 15, "fillColor": "red", "animation": { "type": "patrol", "path": [[100, 50], [700, 50], [700, 200], [100, 200]], "speed": 2 } }, { "type": "Text", "id": "score", "x": 20, "y": 30, "text": "Score: 0", "fontSize": 20, "font": "Arial", "color": "white" } ], "behaviors": [ { "type": "collision", "objects": ["ship", "enemy1"], "action": "gameOver" } ] }`;

Best Practices

Performance

Code Organization

Memory Management

JSON Schema Best Practices

Debugging

Advanced Patterns

Custom Graphics Objects

function CustomShape(x, y, size) { GraphicsObject.call(this, x, y); this.size = size; this.draw = function() { // Custom drawing code using this.canvas this.canvas.beginPath(); // ... drawing operations this.canvas.stroke(); }; this.isInside = function(x, y) { // Custom hit testing logic return false; // Implement based on shape }; this.toJSON = function() { return { type: "CustomShape", x: this.x, y: this.y, size: this.size, color: this.color, fillColor: this.fillColor }; }; } CustomShape.prototype = new GraphicsObject(); // Register custom type with JSON loader GiraffeJSONLoader.prototype.createCustomShape = function(objData) { return new CustomShape(objData.x, objData.y, objData.size); };

Animation Controllers

var GameController = { score: 0, gameObjects: [], processFrame: function(frameNumber) { // Update game state this.updatePhysics(); this.checkCollisions(); this.updateUI(); }, updatePhysics: function() { // Physics simulation }, checkCollisions: function() { // Collision detection }, exportGameState: function() { return { score: this.score, frame: this.currentFrame, objects: this.gameObjects.map(obj => obj.toJSON()) }; } }; canvas.addAnimationListener(GameController);

Scene Management System

var SceneManager = { scenes: {}, currentScene: null, canvas: null, loadScene: function(sceneName, jsonData) { var loader = new GiraffeJSONLoader(); var objects = loader.loadScene(jsonData, this.canvas); this.scenes[sceneName] = { objects: objects, jsonData: jsonData }; return objects; }, switchToScene: function(sceneName) { // Clear current scene if (this.currentScene) { this.clearScene(this.currentScene); } // Load new scene if (this.scenes[sceneName]) { this.currentScene = sceneName; var scene = this.scenes[sceneName]; // Reload objects from JSON var loader = new GiraffeJSONLoader(); scene.objects = loader.loadScene(scene.jsonData, this.canvas); this.canvas.repaint(); } }, clearScene: function(sceneName) { if (this.scenes[sceneName]) { var scene = this.scenes[sceneName]; for (var id in scene.objects) { this.canvas.remove(scene.objects[id]); } } }, saveCurrentScene: function() { if (this.currentScene) { var scene = this.scenes[this.currentScene]; scene.jsonData = exportSceneToJSON(this.canvas, scene.objects); return scene.jsonData; } return null; } };

Browser Compatibility

Giraffe.js is designed to work with HTML5 canvas-supporting browsers:

Troubleshooting

Common Issues

Debug Techniques

// Check if object is being drawn myObject.draw = function() { console.log("Drawing object at: " + this.x + "," + this.y); // ... original draw code }; // Monitor animation performance var frameCount = 0; var startTime = Date.now(); canvas.addAnimationListener({ processFrame: function(frame) { frameCount++; if (frameCount % 60 === 0) { var fps = frameCount / ((Date.now() - startTime) / 1000); console.log("Average FPS: " + fps); } } }); // Validate JSON before loading function validateSceneJSON(jsonString) { try { var scene = JSON.parse(jsonString); if (!scene.objects || !Array.isArray(scene.objects)) { throw new Error("Invalid scene: objects array missing"); } scene.objects.forEach(function(obj, index) { if (!obj.type) { throw new Error("Object at index " + index + " missing type"); } if (obj.x === undefined || obj.y === undefined) { throw new Error("Object at index " + index + " missing position"); } }); return scene; } catch (e) { console.error("JSON validation failed:", e); return null; } }

Class Reference Summary

Core Classes

Drawing Primitives

Advanced Features

Animation Classes

Utility Modules

Quick Start Guide

1. Basic Setup

// HTML <canvas id="myCanvas" width="600" height="400"></canvas> // JavaScript var canvas = new Canvas("myCanvas");

2. Add Graphics (Programmatic)

var circle = new Circle(100, 100, 50) .setFillColor("blue") .setColor("darkblue"); canvas.add(circle); canvas.repaint();

3. Add Graphics (JSON)

var sceneJSON = `{ "objects": [ { "type": "Circle", "x": 100, "y": 100, "radius": 50, "fillColor": "blue", "color": "darkblue" } ] }`; var loader = new GiraffeJSONLoader(); var objects = loader.loadScene(sceneJSON, canvas); canvas.repaint();

4. Enable Interaction

Giraffe.Interactive.setInteractive(canvas); circle.onClick = function(x, y) { alert("Circle clicked!"); };

5. Add Animation

Giraffe.setAnimated(canvas); circle.animate = function(frame) { this.x = 100 + Math.sin(frame * 0.1) * 50; }; canvas.startAnimation(30, 1000, true);

6. Save/Load Scenes

// Save current scene var sceneJSON = exportSceneToJSON(canvas, objects); localStorage.setItem("myScene", sceneJSON); // Load saved scene var savedScene = localStorage.getItem("myScene"); if (savedScene) { var objects = loader.loadScene(savedScene, canvas); }
This comprehensive documentation covers the complete Giraffe.js library functionality, including both programmatic usage and JSON schema-based scene definition. The library provides a solid foundation for building interactive canvas applications with clean object-oriented design patterns, comprehensive animation support, robust user interaction capabilities, and flexible data-driven scene management.