Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit c8515e8e218eae40f556cc12223e6afd1d645184 0 parents
@bmeck authored
Showing with 9,209 additions and 0 deletions.
  1. +112 −0 app.js
  2. +13 −0 node_modules/canvas/.gitignore
  3. 0  node_modules/canvas/.gitmodules
  4. +6 −0 node_modules/canvas/.npmignore
  5. +217 −0 node_modules/canvas/History.md
  6. +21 −0 node_modules/canvas/Makefile
  7. +223 −0 node_modules/canvas/Readme.md
  8. +122 −0 node_modules/canvas/benchmarks/run.js
  9. +113 −0 node_modules/canvas/examples/clock.js
  10. +36 −0 node_modules/canvas/examples/globalAlpha.js
  11. +35 −0 node_modules/canvas/examples/gradients.js
  12. +45 −0 node_modules/canvas/examples/image-src.js
  13. BIN  node_modules/canvas/examples/images/squid.png
  14. +98 −0 node_modules/canvas/examples/kraken.js
  15. +113 −0 node_modules/canvas/examples/live-clock.js
  16. +85 −0 node_modules/canvas/examples/ray.js
  17. +31 −0 node_modules/canvas/examples/resize.js
  18. +117 −0 node_modules/canvas/examples/rhill-voronoi-core-min.js
  19. +46 −0 node_modules/canvas/examples/spark.js
  20. +33 −0 node_modules/canvas/examples/state.js
  21. +41 −0 node_modules/canvas/examples/text.js
  22. +140 −0 node_modules/canvas/examples/voronoi.js
  23. +1 −0  node_modules/canvas/index.js
  24. +48 −0 node_modules/canvas/install
  25. +10 −0 node_modules/canvas/lib/bindings.js
  26. +146 −0 node_modules/canvas/lib/canvas.js
  27. +323 −0 node_modules/canvas/lib/context2d.js
  28. +60 −0 node_modules/canvas/lib/image.js
  29. +29 −0 node_modules/canvas/lib/pixelarray.js
  30. +66 −0 node_modules/canvas/lib/pngstream.js
  31. BIN  node_modules/canvas/out.png
  32. +17 −0 node_modules/canvas/package.json
  33. +339 −0 node_modules/canvas/src/Canvas.cc
  34. +66 −0 node_modules/canvas/src/Canvas.h
  35. +122 −0 node_modules/canvas/src/CanvasGradient.cc
  36. +29 −0 node_modules/canvas/src/CanvasGradient.h
  37. +1,862 −0 node_modules/canvas/src/CanvasRenderingContext2d.cc
  38. +133 −0 node_modules/canvas/src/CanvasRenderingContext2d.h
  39. +722 −0 node_modules/canvas/src/Image.cc
  40. +76 −0 node_modules/canvas/src/Image.h
  41. +69 −0 node_modules/canvas/src/ImageData.cc
  42. +28 −0 node_modules/canvas/src/ImageData.h
  43. +155 −0 node_modules/canvas/src/PixelArray.cc
  44. +33 −0 node_modules/canvas/src/PixelArray.h
  45. +19 −0 node_modules/canvas/src/Point.h
  46. +51 −0 node_modules/canvas/src/closure.h
  47. +427 −0 node_modules/canvas/src/color.cc
  48. +39 −0 node_modules/canvas/src/color.h
  49. +25 −0 node_modules/canvas/src/init.cc
  50. +444 −0 node_modules/canvas/test/canvas.test.js
  51. BIN  node_modules/canvas/test/fixtures/clock.png
  52. +86 −0 node_modules/canvas/test/image.test.js
  53. +106 −0 node_modules/canvas/test/public/app.js
  54. BIN  node_modules/canvas/test/public/face.jpeg
  55. BIN  node_modules/canvas/test/public/state.png
  56. +39 −0 node_modules/canvas/test/public/style.css
  57. +1,853 −0 node_modules/canvas/test/public/tests.js
  58. +61 −0 node_modules/canvas/test/server.js
  59. +9 −0 node_modules/canvas/test/views/layout.jade
  60. +19 −0 node_modules/canvas/test/views/tests.jade
  61. +39 −0 node_modules/canvas/wscript
  62. +11 −0 package.json
112 app.js
@@ -0,0 +1,112 @@
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('canvas')
+ , canvas = new Canvas(320, 320)
+ , ctx = canvas.getContext('2d')
+ , http = require('http');
+
+function getX(angle) {
+ return -Math.sin(angle + Math.PI);
+}
+function getY(angle) {
+ return Math.cos(angle + Math.PI);
+}
+
+function clock(ctx){
+ var now = new Date();
+ ctx.clearRect(0,0,320,320);
+
+ ctx.save();
+ ctx.translate(160,160);
+ ctx.beginPath();
+ ctx.lineWidth = 14;
+ ctx.strokeStyle = '#325FA2';
+ ctx.fillStyle = '#eeeeee';
+ ctx.arc(0,0,142,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.strokeStyle = '#000000';
+ // Hour marks
+ ctx.lineWidth = 8;
+ for (var i=0;i<12;i++){
+ var x = getX(Math.PI/6*i);
+ var y = getY(Math.PI/6*i);
+ ctx.beginPath();
+ ctx.moveTo(x*100,y*100);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+
+ // Minute marks
+ ctx.lineWidth = 5;
+ for (i=0;i<60;i++){
+ if (i%5!=0) {
+ var x = getX(Math.PI/30*i);
+ var y = getY(Math.PI/30*i);
+ ctx.beginPath();
+ ctx.moveTo(x*117,y*117);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+ }
+
+ var sec = now.getSeconds();
+ var min = now.getMinutes();
+ var hr = now.getHours();
+ hr = hr>=12 ? hr-12 : hr;
+
+ ctx.fillStyle = "black";
+
+ // write Hours
+ var x = getX(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ var y = getY(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ ctx.lineWidth = 14;
+ ctx.beginPath();
+ ctx.moveTo(x*-20,y*-20);
+ ctx.lineTo(x*80,y*80);
+ ctx.stroke();
+
+ // write Minutes
+ var x = getX((Math.PI/30)*min + (Math.PI/1800)*sec);
+ var y = getY((Math.PI/30)*min + (Math.PI/1800)*sec);
+
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(x*-28,y*-28);
+ ctx.lineTo(x*112,y*112);
+ ctx.stroke();
+
+ // Write seconds
+ var x = getX(sec * Math.PI/30);
+ var y = getY(sec * Math.PI/30);
+ ctx.strokeStyle = "#D40000";
+ ctx.fillStyle = "#D40000";
+ ctx.lineWidth = 6;
+ ctx.beginPath();
+ ctx.moveTo(x*-30,y*-30);
+ ctx.lineTo(x*83,y*83);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0,0,10,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(x*95,y*95,10,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fillStyle = "#555";
+ ctx.arc(0,0,3,0,Math.PI*2,true);
+ ctx.fill();
+
+ ctx.restore();
+}
+
+http.createServer(function (req, res) {
+ clock(ctx);
+ res.writeHead(200, { 'Content-Type': 'text/html' });
+ res.end(''
+ + '<meta http-equiv="refresh" content="1;" />'
+ + '<img src="' + canvas.toDataURL() + '" />');
+}).listen(3000);
+console.log('Server started on port 3000');
13 node_modules/canvas/.gitignore
@@ -0,0 +1,13 @@
+build
+.DS_Store
+.lock-wscript
+test/images/*.png
+examples/*.png
+testing
+test.png
+.pomo
+node_modules
+
+# Vim cruft
+*.swp
+*.un~
0  node_modules/canvas/.gitmodules
No changes.
6 node_modules/canvas/.npmignore
@@ -0,0 +1,6 @@
+testing
+build
+benchmarks
+examples
+support
+test
217 node_modules/canvas/History.md
@@ -0,0 +1,217 @@
+
+0.8.1 / 2011-10-31
+==================
+
+ * Added 0.5.x support [TooTallNate]
+ * Fixed `measureText().width`. Closes #126
+
+0.8.0 / 2011-10-28
+==================
+
+ * Added data uri support. Closes #49
+
+0.7.3 / 2011-09-14
+==================
+
+ * Added better lineTo() / moveTo() exception messages
+
+0.7.2 / 2011-08-30
+==================
+
+ * Changed: prefix some private methods with _
+
+0.7.1 / 2011-08-25
+==================
+
+ * Added better image format detection
+ * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD
+
+0.7.0 / 2011-07-12
+==================
+
+ * Added GIF support [Brian McKinney]
+
+0.6.0 / 2011-06-04
+==================
+
+ * Added `Image#src=Buffer` support. Closes #91
+ * Added `devDependencies`
+ * Added `source-atop` test
+ * Added _image-src.js_ example
+ * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()`
+ * Fixed v8 memory hint when resizing canvas [atomizer]
+
+0.5.4 / 2011-04-20
+==================
+
+ * Added; special case of zero-width rectangle [atomizer]
+ * Fixed; do not clamp arguments to integer values [atomizer]
+ * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer]
+ * Fixed; `restorePath()`: clear current path before appending [atomizer]
+
+0.5.3 / 2011-04-11
+==================
+
+ * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte]
+
+0.5.2 / 2011-04-09
+==================
+
+ * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte]
+
+0.5.1 / 2011-03-16
+==================
+
+ * Fixed (kinda) `img.src=` error handling
+ * Fixed; move closure.h down for malloc ref. Closes #80
+
+0.5.0 / 2011-03-14
+==================
+
+ * Added several more operators (color-dodge, color-burn, difference, etc)
+ * Performance; no longer re-allocating `closure->data` for each png write
+ * Fixed freeing of `Context2d` states
+ * Fixed text alignment / baseline [Olaf]
+ * Fixed HandleScopes [Olaf]
+ * Fixed small misc memory leaks
+ * Fixed `Buffer` usage for node 0.4.x
+
+0.4.3 / 2011-01-11
+==================
+
+ * Fixed font family dereferencing. Closes #72
+ * Fixed; stripping of quotes from font-family before applying
+ * Fixed duplicate textAlign getter
+ * Removed sans-serif default of _Arial_
+
+0.4.2 / 2010-12-28
+==================
+
+ * Fixed font size growing issue after successive calls. Closes #70
+
+0.4.1 / 2010-12-18
+==================
+
+ * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68
+
+0.4.0 / 2010-12-12
+==================
+
+ * Added `drawImage()` with `Canvas` instance support. Closes #67
+
+0.3.3 / 2010-11-30
+==================
+
+ * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_
+ * Fixed; pre-multiply `putImageData()` components
+ * Fixed; `PixelArray` data is not premultiplied
+
+0.3.2 / 2010-11-26
+==================
+
+ * Added --profile option to config
+ * Fixed `eio_custom` segfault(s). Closes #46
+ * Fixed two named colors. Closes #62 [thanks noonat]
+ * Fixed a few warnings
+ * Fixed; freeing data in `Image::loadJPEG()` on failure
+ * Fixed; include _jpeglib_ only when __HAVE_JPEG__
+ * Fixed; using `strstr()` instead of `strnstr()`
+
+0.3.1 / 2010-11-24
+==================
+
+ * Fixed; `Image` loading is sync until race-condition is resolved
+ * Fixed; `Image::loadJPEG()` return status based on errno
+
+0.3.0 / 2010-11-24
+==================
+
+ * Added arcTo(). Closes #11
+ * Added c color parser, _./examples/ray.js_ is now twice as fast
+ * Fixed `putImageData()` bug messing up rgba channels
+
+0.2.1 / 2010-11-19
+==================
+
+ * Added image _resize_ example
+ * Fixed canvas resizing via `{width,height}=`. Closes #57
+ * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext
+ * Fixed async image loading (test server still messed)
+
+0.2.0 / 2010-11-18
+==================
+
+ * Added jpeg `Image` support (when libjpeg is available)
+ * Added _hsl_ / _hsla_ color support. [Tom Carden]
+
+0.1.0 / 2010-11-17
+==================
+
+ * Added `Image`
+ * Added `ImageData`
+ * Added `PixelArray`
+ * Added `CanvasRenderingContext2d#drawImage()`
+ * Added `CanvasRenderingContext2d#getImageData()`
+ * Added `CanvasRenderingContext2d#createImageData()`
+ * Added kraken blur benchmark example
+ * Added several new tests
+ * Fixed instanceof checks for many c++ methods
+ * Fixed test runner in firefox [Don Park]
+
+0.0.8 / 2010-11-12
+==================
+
+ * Added `CanvasRenderingContext2d#drawImage()`
+ * Fixed `free()` call missing stdlib
+ * Fixed Image#{width,height} initialization to 0
+ * Fixed; load image on non-LOADING state
+
+0.0.7 / 2010-11-12
+==================
+
+ * Fixed _lighter_ for older versions of cairo
+
+0.0.6 / 2010-11-12
+==================
+
+ * Added `Image`
+ * Added conditional support for cairo 1.10.0 operators
+
+0.0.5 / 2010-11-10
+==================
+
+ * Added custom port support to _test/server.js_
+ * Added more global composite operator support
+ * Added `Context2d#antialias=`
+ * Added _voronoi_ example
+ * Added -D__NDEBUG__ to default build
+ * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park]
+ * Fixed getter bug preventing patterns from being returned via `fillStyle` etc
+
+ * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc()
+ * Fixed; free `Canvas::ToBuffer()` closure data
+
+0.0.4 / 2010-11-09
+==================
+
+ * Bump to fix npm engine cache bug...
+
+0.0.3 / 2010-11-09
+==================
+
+ * Added async `toDataURL()` support
+ * Added async `toBuffer()` support
+ * Removed buffer utils
+
+0.0.2 / 2010-11-08
+==================
+
+ * Added shadow support (faster/better gaussian blur to come)
+ * Added node v0.3 support [Don Park]
+ * Added -O3 to build
+ * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()`
+
+0.0.1 / 2010-11-04
+==================
+
+ * Initial release
21 node_modules/canvas/Makefile
@@ -0,0 +1,21 @@
+
+ADDON = build/default/canvas.node
+
+$(ADDON): src/*.cc
+ node-waf configure build
+
+test: $(ADDON)
+ @./node_modules/.bin/expresso \
+ -I lib \
+ test/*.test.js
+
+test-server: $(ADDON)
+ @node test/server.js
+
+benchmark:
+ @node benchmarks/run.js
+
+clean:
+ node-waf distclean
+
+.PHONY: test test-server benchmark clean
223 node_modules/canvas/Readme.md
@@ -0,0 +1,223 @@
+# node-canvas
+
+ Node canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org).
+
+## Authors
+
+ - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
+
+## Installation
+
+ $ npm install canvas
+
+If not previously installed, you will want to install the [cairo graphics library](http://cairographics.org/download/) version _>= 1.8.6_ first using the package manager available to you, or [building from source](https://github.com/LearnBoost/node-canvas/wiki/_pages).
+
+## Screencasts
+
+ - [Introduction](http://screenr.com/CTk)
+
+## Example
+
+```javascript
+var Canvas = require('canvas')
+ , canvas = new Canvas(200,200)
+ , ctx = canvas.getContext('2d');
+
+ctx.font = '30px Impact';
+ctx.rotate(.1);
+ctx.fillText("Awesome!", 50, 100);
+
+var te = ctx.measureText('Awesome!');
+ctx.strokeStyle = 'rgba(0,0,0,0.5)';
+ctx.beginPath();
+ctx.lineTo(50, 102);
+ctx.lineTo(50 + te.width, 102);
+ctx.stroke();
+
+console.log('<img src="' + canvas.toDataURL() + '" />');
+```
+
+## Non-Standard API
+
+ node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers.
+
+### Image#src=Buffer
+
+ node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O.
+
+```javascript
+fs.readFile(__dirname + '/images/squid.png', function(err){
+ if (err) throw err;
+ img = new Image;
+ img.src = squid;
+ ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4);
+});
+```
+
+ Below is an example of a canvas drawing it-self as the source several time:
+
+```javascript
+var img = new Image;
+img.src = canvas.toBuffer();
+ctx.drawImage(img, 0, 0, 50, 50);
+ctx.drawImage(img, 50, 0, 50, 50);
+ctx.drawImage(img, 100, 0, 50, 50);
+```
+
+### Canvas#createPNGStream()
+
+ To create a `PNGStream` simple call `canvas.createPNGStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted.
+
+```javascript
+var fs = require('fs')
+ , out = fs.createWriteStream(__dirname + '/text.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
+
+stream.on('end', function(){
+ console.log('saved png');
+});
+```
+
+Currently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`.
+
+### Canvas#toBuffer()
+
+A call to `Canvas#toBuffer()` will return a node `Buffer` instance containing all of the PNG data.
+
+```javascript
+canvas.toBuffer();
+```
+
+### Canvas#toBuffer() async
+
+Optionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`.
+
+```javascript
+canvas.toBuffer(function(err, buf){
+
+});
+```
+
+### Canvas#toDataURL() async
+
+Optionally we may pass a callback function to `Canvas#toDataURL()`, and this process will be performed asynchronously, and will `callback(err, str)`.
+
+```javascript
+canvas.toDataURL(function(err, str){
+
+});
+```
+
+or specify the mime type:
+
+```javascript
+canvas.toDataURL('image/png', function(err, str){
+
+});
+```
+
+### CanvasRenderingContext2d#patternQuality
+
+Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.
+
+ - fast
+ - good
+ - best
+
+### Global Composite Operations
+
+In addition to those specified and commonly implemented by browsers, the following have been added:
+
+ - multiply
+ - screen
+ - overlay
+ - hard-light
+ - soft-light
+ - hsl-hue
+ - hsl-saturation
+ - hsl-color
+ - hsl-luminosity
+
+## Anti-Aliasing
+
+ Set anti-aliasing mode
+
+ - default
+ - none
+ - gray
+ - subpixel
+
+ For example:
+
+```javascript
+ctx.antialias = 'none';
+```
+
+## Benchmarks
+
+ Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself.
+
+## Contribute
+
+ Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/LearnBoost/node-canvas/issues) for existing issues.
+
+## Examples
+
+ Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser.
+
+## Testing
+
+If you have not previously, init git submodules:
+
+ $ git submodule update --init
+
+Build node-canvas:
+
+ $ node-waf configure build
+
+Unit tests:
+
+ $ make test
+
+Visual tests:
+
+ $ make test-server
+
+## Versions
+
+Tested with and designed for:
+
+ - node 0.4.2
+ - cairo 1.8.6
+
+For node 0.2.x `node-canvas` <= 0.4.3 may be used,
+0.5.0 and above are designed for node 0.4.x only.
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2010 LearnBoost &lt;dev@learnboost.ca&gt;
+
+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.
122 node_modules/canvas/benchmarks/run.js
@@ -0,0 +1,122 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(200, 200)
+ , largeCanvas = new Canvas(1000, 1000)
+ , ctx = canvas.getContext('2d');
+
+var times = 10000;
+console.log('\n \x1b[33m%s\x1b[0m times\n', times);
+
+function bm(label, overrideTimes, fn) {
+ var start = new Date
+ , n = times;
+
+ if ('function' == typeof overrideTimes) {
+ fn = overrideTimes;
+ } else {
+ n = overrideTimes;
+ label += ' (' + n + ' times)';
+ }
+
+ var pending = n;
+
+ function done(){
+ var duration = (new Date - start) / 1000;
+ console.log(' - \x1b[33m%s\x1b[0m %ss', label, duration);
+ }
+
+ if (fn.length) {
+ while (n--) fn(function(){
+ --pending || done();
+ });
+ } else {
+ while (n--) fn();
+ done();
+ }
+}
+
+// node-canvas
+
+bm('lineTo()', function(){
+ ctx.lineTo(0, 50);
+});
+
+bm('arc()', function(){
+ ctx.arc(75,75,50,0,Math.PI*2,true);
+});
+
+bm('fillStyle= hex', function(){
+ ctx.fillStyle = '#FFCCAA';
+});
+
+bm('fillStyle= rgba()', function(){
+ ctx.fillStyle = 'rgba(0,255,80,1)';
+});
+
+bm('fillRect()', function(){
+ ctx.fillRect(50, 50, 100, 100);
+});
+
+bm('strokeRect()', function(){
+ ctx.strokeRect(50, 50, 100, 100);
+});
+
+bm('linear gradients', function(){
+ var lingrad = ctx.createLinearGradient(0,50,0,95);
+ lingrad.addColorStop(0.5, '#000');
+ lingrad.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = lingrad;
+ ctx.fillRect(10,10,130,130);
+});
+
+bm('toBuffer() 200x200', 50, function(){
+ canvas.toBuffer();
+});
+
+bm('toBuffer() 1000x1000', 50, function(){
+ largeCanvas.toBuffer();
+});
+
+bm('toBuffer().toString("base64") 200x200', 50, function(){
+ canvas.toBuffer().toString('base64');
+});
+
+bm('toDataURL() 200x200', 50, function(){
+ canvas.toDataURL();
+});
+
+bm('moveTo() / arc() / stroke()', function(){
+ ctx.beginPath();
+ ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
+ ctx.moveTo(110,75);
+ ctx.arc(75,75,35,0,Math.PI,false); // Mouth
+ ctx.moveTo(65,65);
+ ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye
+ ctx.moveTo(95,65);
+ ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye
+ ctx.stroke();
+});
+
+bm('createImageData(300,300)', function(){
+ ctx.createImageData(300,300);
+});
+
+bm('getImageData(0,0,100,100)', function(){
+ ctx.getImageData(0,0,100,100);
+});
+
+// bm('PNGStream 200x200', 50, function(done){
+// var stream = canvas.createSyncPNGStream();
+// stream.on('data', function(chunk){
+// // whatever
+// });
+// stream.on('end', function(){
+// done();
+// });
+// });
+
+console.log();
113 node_modules/canvas/examples/clock.js
@@ -0,0 +1,113 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(320, 320)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+function getX(angle) {
+ return -Math.sin(angle + Math.PI);
+}
+function getY(angle) {
+ return Math.cos(angle + Math.PI);
+}
+
+function clock(ctx){
+ var now = new Date();
+ ctx.clearRect(0,0,320,320);
+
+ ctx.save();
+ ctx.translate(160,160);
+ ctx.beginPath();
+ ctx.lineWidth = 14;
+ ctx.strokeStyle = '#325FA2';
+ ctx.fillStyle = '#eeeeee';
+ ctx.arc(0,0,142,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.strokeStyle = '#000000';
+ // Hour marks
+ ctx.lineWidth = 8;
+ for (var i=0;i<12;i++){
+ var x = getX(Math.PI/6*i);
+ var y = getY(Math.PI/6*i);
+ ctx.beginPath();
+ ctx.moveTo(x*100,y*100);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+
+ // Minute marks
+ ctx.lineWidth = 5;
+ for (i=0;i<60;i++){
+ if (i%5!=0) {
+ var x = getX(Math.PI/30*i);
+ var y = getY(Math.PI/30*i);
+ ctx.beginPath();
+ ctx.moveTo(x*117,y*117);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+ }
+
+ var sec = now.getSeconds();
+ var min = now.getMinutes();
+ var hr = now.getHours();
+ hr = hr>=12 ? hr-12 : hr;
+
+ ctx.fillStyle = "black";
+
+ // write Hours
+ var x = getX(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ var y = getY(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ ctx.lineWidth = 14;
+ ctx.beginPath();
+ ctx.moveTo(x*-20,y*-20);
+ ctx.lineTo(x*80,y*80);
+ ctx.stroke();
+
+ // write Minutes
+ var x = getX((Math.PI/30)*min + (Math.PI/1800)*sec);
+ var y = getY((Math.PI/30)*min + (Math.PI/1800)*sec);
+
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(x*-28,y*-28);
+ ctx.lineTo(x*112,y*112);
+ ctx.stroke();
+
+ // Write seconds
+ var x = getX(sec * Math.PI/30);
+ var y = getY(sec * Math.PI/30);
+ ctx.strokeStyle = "#D40000";
+ ctx.fillStyle = "#D40000";
+ ctx.lineWidth = 6;
+ ctx.beginPath();
+ ctx.moveTo(x*-30,y*-30);
+ ctx.lineTo(x*83,y*83);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0,0,10,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(x*95,y*95,10,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fillStyle = "#555";
+ ctx.arc(0,0,3,0,Math.PI*2,true);
+ ctx.fill();
+
+ ctx.restore();
+}
+
+clock(ctx);
+
+var out = fs.createWriteStream(__dirname + '/clock.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
36 node_modules/canvas/examples/globalAlpha.js
@@ -0,0 +1,36 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(150, 150)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+ctx.fillStyle = '#FD0';
+ctx.fillRect(0,0,75,75);
+ctx.fillStyle = '#6C0';
+ctx.fillRect(75,0,75,75);
+ctx.fillStyle = '#09F)';
+ctx.fillRect(0,75,75,75);
+ctx.fillStyle = '#F30';
+ctx.fillRect(75,75,150,150);
+ctx.fillStyle = '#FFF';
+
+// set transparency value
+ctx.globalAlpha = 0.2;
+
+// Draw semi transparent circles
+for (i=0;i<7;i++){
+ ctx.beginPath();
+ ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
+ ctx.fill();
+}
+
+var out = fs.createWriteStream(__dirname + '/globalAlpha.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
35 node_modules/canvas/examples/gradients.js
@@ -0,0 +1,35 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(320, 320)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+// Create gradients
+var lingrad = ctx.createLinearGradient(0,0,0,150);
+lingrad.addColorStop(0, '#00ABEB');
+lingrad.addColorStop(0.5, '#fff');
+lingrad.addColorStop(0.5, '#26C000');
+lingrad.addColorStop(1, '#fff');
+
+var lingrad2 = ctx.createLinearGradient(0,50,0,95);
+lingrad2.addColorStop(0.5, '#000');
+lingrad2.addColorStop(1, 'rgba(0,0,0,0)');
+
+// assign gradients to fill and stroke styles
+ctx.fillStyle = lingrad;
+ctx.strokeStyle = lingrad2;
+
+// draw shapes
+ctx.fillRect(10,10,130,130);
+ctx.strokeRect(50,50,50,50);
+
+var out = fs.createWriteStream(__dirname + '/gradients.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
45 node_modules/canvas/examples/image-src.js
@@ -0,0 +1,45 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , Image = Canvas.Image
+ , canvas = new Canvas(200, 200)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+ctx.fillRect(0,0,150,150);
+ctx.save();
+
+ctx.fillStyle = '#09F'
+ctx.fillRect(15,15,120,120);
+
+ctx.save();
+ctx.fillStyle = '#FFF'
+ctx.globalAlpha = 0.5;
+ctx.fillRect(30,30,90,90);
+
+ctx.restore();
+ctx.fillRect(45,45,60,60);
+
+ctx.restore();
+ctx.fillRect(60,60,30,30);
+
+var img = new Image;
+img.src = canvas.toBuffer();
+ctx.drawImage(img, 0, 0, 50, 50);
+ctx.drawImage(img, 50, 0, 50, 50);
+ctx.drawImage(img, 100, 0, 50, 50);
+
+var squid = fs.readFileSync(__dirname + '/images/squid.png');
+img = new Image;
+img.src = squid;
+ctx.drawImage(img, 30, 50, img.width / 4, img.height / 4);
+
+var out = fs.createWriteStream(__dirname + '/image-src.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
BIN  node_modules/canvas/examples/images/squid.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 node_modules/canvas/examples/kraken.js
@@ -0,0 +1,98 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , Image = Canvas.Image
+ , canvas = new Canvas(400, 267)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+var img = new Image;
+
+img.onload = function(){
+ ctx.drawImage(img,0,0);
+};
+
+img.src = __dirname + '/images/squid.png';
+
+
+var sigma = 10; // radius
+var kernel, kernelSize, kernelSum;
+buildKernel();
+
+function buildKernel() {
+ var ss = sigma * sigma;
+ var factor = 2 * Math.PI * ss;
+ kernel = [];
+ kernel.push([]);
+ var i = 0, j;
+ do {
+ var g = Math.exp(-(i * i) / (2 * ss)) / factor;
+ if (g < 1e-3) break;
+ kernel[0].push(g);
+ ++i;
+ } while (i < 7);
+ kernelSize = i;
+ for (j = 1; j < kernelSize; ++j) {
+ kernel.push([]);
+ for (i = 0; i < kernelSize; ++i) {
+ var g = Math.exp(-(i * i + j * j) / (2 * ss)) / factor;
+ kernel[j].push(g);
+ }
+ }
+ kernelSum = 0;
+ for (j = 1 - kernelSize; j < kernelSize; ++j) {
+ for (i = 1 - kernelSize; i < kernelSize; ++i) {
+ kernelSum += kernel[Math.abs(j)][Math.abs(i)];
+ }
+ }
+}
+
+function blurTest() {
+ console.log('... running');
+
+ var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ var width = imgData.width, height = imgData.height;
+ var data = imgData.data;
+
+ var len = data.length;
+ var startTime = (new Date()).getTime();
+
+ for (var y = 0; y < height; ++y) {
+ for (var x = 0; x < width; ++x) {
+ var r = 0, g = 0, b = 0, a = 0;
+ for (j = 1 - kernelSize; j < kernelSize; ++j) {
+ if (y + j < 0 || y + j >= height) continue;
+ for (i = 1 - kernelSize; i < kernelSize; ++i) {
+ if (x + i < 0 || x + i >= width) continue;
+ r += data[4 * ((y + j) * width + (x + i)) + 0] * kernel[Math.abs(j)][Math.abs(i)];
+ g += data[4 * ((y + j) * width + (x + i)) + 1] * kernel[Math.abs(j)][Math.abs(i)];
+ b += data[4 * ((y + j) * width + (x + i)) + 2] * kernel[Math.abs(j)][Math.abs(i)];
+ a += data[4 * ((y + j) * width + (x + i)) + 3] * kernel[Math.abs(j)][Math.abs(i)];
+ }
+ }
+ data[4 * (y * width + x) + 0] = r / kernelSum;
+ data[4 * (y * width + x) + 1] = g / kernelSum;
+ data[4 * (y * width + x) + 2] = b / kernelSum;
+ data[4 * (y * width + x) + 3] = a / kernelSum;
+ }
+ }
+ var finishTime = Date.now() - startTime;
+ for (var i = 0; i < data.length; i++) {
+ imgData.data[i] = data[i];
+ }
+ //imgData.data = data;
+ ctx.putImageData(imgData, 0, 0);
+ console.log('... finished in %dms', finishTime);
+}
+
+blurTest();
+
+var out = fs.createWriteStream(__dirname + '/kraken.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
113 node_modules/canvas/examples/live-clock.js
@@ -0,0 +1,113 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(320, 320)
+ , ctx = canvas.getContext('2d')
+ , http = require('http');
+
+function getX(angle) {
+ return -Math.sin(angle + Math.PI);
+}
+function getY(angle) {
+ return Math.cos(angle + Math.PI);
+}
+
+function clock(ctx){
+ var now = new Date();
+ ctx.clearRect(0,0,320,320);
+
+ ctx.save();
+ ctx.translate(160,160);
+ ctx.beginPath();
+ ctx.lineWidth = 14;
+ ctx.strokeStyle = '#325FA2';
+ ctx.fillStyle = '#eeeeee';
+ ctx.arc(0,0,142,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.strokeStyle = '#000000';
+ // Hour marks
+ ctx.lineWidth = 8;
+ for (var i=0;i<12;i++){
+ var x = getX(Math.PI/6*i);
+ var y = getY(Math.PI/6*i);
+ ctx.beginPath();
+ ctx.moveTo(x*100,y*100);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+
+ // Minute marks
+ ctx.lineWidth = 5;
+ for (i=0;i<60;i++){
+ if (i%5!=0) {
+ var x = getX(Math.PI/30*i);
+ var y = getY(Math.PI/30*i);
+ ctx.beginPath();
+ ctx.moveTo(x*117,y*117);
+ ctx.lineTo(x*125,y*125);
+ ctx.stroke();
+ }
+ }
+
+ var sec = now.getSeconds();
+ var min = now.getMinutes();
+ var hr = now.getHours();
+ hr = hr>=12 ? hr-12 : hr;
+
+ ctx.fillStyle = "black";
+
+ // write Hours
+ var x = getX(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ var y = getY(hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec);
+ ctx.lineWidth = 14;
+ ctx.beginPath();
+ ctx.moveTo(x*-20,y*-20);
+ ctx.lineTo(x*80,y*80);
+ ctx.stroke();
+
+ // write Minutes
+ var x = getX((Math.PI/30)*min + (Math.PI/1800)*sec);
+ var y = getY((Math.PI/30)*min + (Math.PI/1800)*sec);
+
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(x*-28,y*-28);
+ ctx.lineTo(x*112,y*112);
+ ctx.stroke();
+
+ // Write seconds
+ var x = getX(sec * Math.PI/30);
+ var y = getY(sec * Math.PI/30);
+ ctx.strokeStyle = "#D40000";
+ ctx.fillStyle = "#D40000";
+ ctx.lineWidth = 6;
+ ctx.beginPath();
+ ctx.moveTo(x*-30,y*-30);
+ ctx.lineTo(x*83,y*83);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0,0,10,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(x*95,y*95,10,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fillStyle = "#555";
+ ctx.arc(0,0,3,0,Math.PI*2,true);
+ ctx.fill();
+
+ ctx.restore();
+}
+
+http.createServer(function (req, res) {
+ clock(ctx);
+ res.writeHead(200, { 'Content-Type': 'text/html' });
+ res.end(''
+ + '<meta http-equiv="refresh" content="1;" />'
+ + '<img src="' + canvas.toDataURL() + '" />');
+}).listen(3000);
+console.log('Server started on port 3000');
85 node_modules/canvas/examples/ray.js
@@ -0,0 +1,85 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(243 * 4, 243)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+function render(level){
+ ctx.fillStyle = getPointColour(122,122);
+ ctx.fillRect(0,0,240,240);
+ renderLevel(level,81,0);
+}
+
+function renderLevel(minimumLevel,level,y){
+ for (var x=0; x < 243 / level; ++x) {
+ drawBlock(x,y,level);
+ }
+ for (var x=0; x < 243 / level; x+=3){
+ drawBlock(x,y+1,level);
+ drawBlock(x+2,y+1,level);
+ }
+ for (var x=0; x < 243 / level; ++x){
+ drawBlock(x,y+2,level);
+ }
+ if ((y += 3) >= 243 / level){
+ y=0;
+ level /= 3;
+ }
+ if (level >= minimumLevel){
+ renderLevel(minimumLevel, level, y);
+ }
+}
+
+function drawBlock(x,y,level){
+ ctx.fillStyle = getPointColour(
+ x * level + (level-1) / 2
+ , y * level + (level-1) / 2);
+
+ ctx.fillRect(
+ x * level
+ , y * level
+ , level
+ , level
+ );
+}
+
+function getPointColour(x,y){
+ x= x / 121.5 - 1;
+ y= -y / 121.5 + 1;
+ var x2y2 = x * x + y * y;
+ if (x2y2 > 1){
+ return '#000';
+ } else {
+ var root = Math.sqrt(1 - x2y2);
+ var x3d = x * 0.7071067812 + root / 2 - y / 2;
+ var y3d = x * 0.7071067812 - root / 2 + y / 2;
+ var z3d = 0.7071067812 * root + 0.7071067812 * y;
+ var brightness= -x / 2 + root * 0.7071067812 + y / 2;
+ if (brightness < 0) brightness = 0;
+ return ''
+ + 'rgb(' + Math.round(brightness * 127.5 * (1 - y3d))
+ + ',' + Math.round(brightness * 127.5 * (x3d + 1))
+ + ',' + Math.round(brightness * 127.5 * (z3d + 1))
+ + ')'
+ ;
+ }
+}
+
+var start = new Date;
+render(10);
+ctx.translate(243,0);
+render(6);
+ctx.translate(243,0);
+render(3);
+ctx.translate(243,0);
+render(1);
+console.log('Rendered in %s seconds', (new Date - start) / 1000);
+
+canvas.toBuffer(function(err, buf){
+ if (err) throw err;
+ fs.writeFile(__dirname + '/ray.png', buf);
+});
31 node_modules/canvas/examples/resize.js
@@ -0,0 +1,31 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , Image = Canvas.Image
+ , fs = require('fs');
+
+var img = new Image
+ , start = new Date;
+
+img.onerror = function(err){
+ throw err;
+};
+
+img.onload = function(){
+ var width = img.width / 2
+ , height = img.height / 2
+ , canvas = new Canvas(width, height)
+ , ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0, width, height);
+ canvas.toBuffer(function(err, buf){
+ fs.writeFile(__dirname + '/resize.png', buf, function(){
+ console.log('Resized and saved in %dms', new Date - start);
+ });
+ });
+};
+
+img.src = __dirname + '/images/squid.png';
+
117 node_modules/canvas/examples/rhill-voronoi-core-min.js
@@ -0,0 +1,117 @@
+/*!
+A custom Javascript implementation of Steven J. Fortune's algorithm to
+compute Voronoi diagrams.
+Copyright (C) 2010 Raymond Hill
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*****
+
+Author: Raymond Hill (rhill@raymondhill.net)
+File: rhill-voronoi-core-min.js
+Version: 0.9
+Date: Sep. 21, 2010
+Description: This is my personal Javascript implementation of
+Steven Fortune's algorithm to generate Voronoi diagrams.
+
+Portions of this software use, or depend on the work of:
+
+ "Fortune's algorithm" by Steven J. Fortune: For his clever
+ algorithm to compute Voronoi diagrams.
+ http://ect.bell-labs.com/who/sjf/
+
+ "The Liang-Barsky line clipping algorithm in a nutshell!" by Daniel White,
+ to efficiently clip a line within a rectangle.
+ http://www.skytopia.com/project/articles/compsci/clipping.html
+
+*****
+
+Usage:
+
+ var vertices = [{x:300,y:300}, {x:100,y:100}, {x:200,y:500}, {x:250,y:450}, {x:600,y:150}];
+ // xl, xr means x left, x right
+ // yt, yb means y top, y bottom
+ var bbox = {xl:0, xr:800, yt:0, yb:600};
+ var voronoi = new Voronoi();
+ // pass an array of objects, each of which exhibits x and y properties
+ voronoi.setSites(vertices);
+ // pass an object which exhibits xl, xr, yt, yb properties. The bounding
+ // box will be used to connect unbound edges, and to close open cells
+ result = voronoi.compute(bbox);
+ // render, further analyze, etc.
+
+Return value:
+ An object with the following properties:
+
+ result.sites = an array of unordered, unique Voronoi.Site objects underlying the Voronoi diagram.
+ result.edges = an array of unordered, unique Voronoi.Edge objects making up the Voronoi diagram.
+ result.cells = a dictionary of Voronoi.Cell object making up the Voronoi diagram. The Voronoi.Cell
+ in the dictionary are keyed on their associated Voronoi.Site's unique id.
+ result.execTime = the time it took to compute the Voronoi diagram, in milliseconds.
+
+Voronoi.Site object:
+ id: a unique id identifying this Voronoi site.
+ x: the x position of this Voronoi site.
+ y: the y position of this Voronoi site.
+ destroy(): mark this Voronoi site object as destroyed, it will be removed from the
+ internal collection and won't be part of the next Voronoi diagram computation.
+
+ When adding vertices to the Voronoi object, through Voronoi.setSites() or
+ Voronoi.addSites(), an internal collection of matching Voronoi.Site object is maintained,
+ which is read accessible at all time through Voronoi.getSites(). You are allowed to
+ change the x and/or y properties of any Voronoi.Site object in the array, before
+ launching the computation of the Voronoi diagram. However, do *not* change the id
+ of any Voronoi.Site object, this could break the computation of the Voronoi diagram.
+
+Voronoi.Edge object:
+ id: a unique id identifying this Voronoi edge.
+ lSite: the Voronoi.Site object at the left of this Voronoi.Edge object.
+ rSite: the Voronoi.Site object at the right of this Voronoi.Edge object (can be null).
+ va: the Voronoi.Vertex object defining the start point (relative to the Voronoi.Site
+ on the left) of this Voronoi.Edge object.
+ vb: the Voronoi.Vertex object defining the end point (relative to Voronoi.Site on
+ the left) of this Voronoi.Edge object.
+
+ For edges which are used to close open cells (using the supplied bounding box), the
+ rSite property will be null.
+
+Voronoi.Cells object:
+ A collection of Voronoi.Cell objects, keyed on the id of the associated Voronoi.Site
+ object.
+ numCells: the number of Voronoi.Cell objects in the collection.
+
+Voronoi.Cell object:
+ site: the Voronoi.Site object associated with the Voronoi cell.
+ halfedges: an array of Voronoi.Halfedge objects, ordered counterclockwise, defining the
+ polygon for this Voronoi cell.
+
+Voronoi.Halfedge object:
+ site: the Voronoi.Site object owning this Voronoi.Halfedge object.
+ edge: a reference to the unique Voronoi.Edge object underlying this Voronoi.Halfedge object.
+ getStartpoint(): a method returning a Voronoi.Vertex for the start point of this
+ halfedge. Keep in mind halfedges are always countercockwise.
+ getEndpoint(): a method returning a Voronoi.Vertex for the end point of this
+ halfedge. Keep in mind halfedges are always countercockwise.
+
+Voronoi.Vertex object:
+ x: the x coordinate.
+ y: the y coordinate.
+
+*/
+function Voronoi(){this.sites=[];this.siteEvents=[];this.circEvents=[];this.arcs=[];this.edges=[];this.cells=new this.Cells()}Voronoi.prototype.SITE_EVENT=0;Voronoi.prototype.CIRCLE_EVENT=1;Voronoi.prototype.VOID_EVENT=-1;Voronoi.prototype.sqrt=Math.sqrt;Voronoi.prototype.abs=Math.abs;Voronoi.prototype.floor=Math.floor;Voronoi.prototype.random=Math.random;Voronoi.prototype.round=Math.round;Voronoi.prototype.min=Math.min;Voronoi.prototype.max=Math.max;Voronoi.prototype.pow=Math.pow;Voronoi.prototype.isNaN=isNaN;Voronoi.prototype.PI=Math.PI;Voronoi.prototype.EPSILON=1e-5;Voronoi.prototype.equalWithEpsilon=function(a,b){return this.abs(a-b)<1e-5};Voronoi.prototype.greaterThanWithEpsilon=function(a,b){return(a-b)>1e-5};Voronoi.prototype.greaterThanOrEqualWithEpsilon=function(a,b){return(b-a)<1e-5};Voronoi.prototype.lessThanWithEpsilon=function(a,b){return(b-a)>1e-5};Voronoi.prototype.lessThanOrEqualWithEpsilon=function(a,b){return(a-b)<1e-5};Voronoi.prototype.Beachsection=function(a){this.site=a;this.edge=null;this.sweep=-Infinity;this.lid=0;this.circleEvent=undefined};Voronoi.prototype.Beachsection.prototype.sqrt=Math.sqrt;Voronoi.prototype.Beachsection.prototype._leftParabolicCut=function(a,c,d){var e=a.x;var f=a.y;if(f==d){return e}var g=c.x;var h=c.y;if(h==d){return g}if(f==h){return(e+g)/2}var i=f-d;var j=h-d;var k=g-e;var l=1/i-1/j;var b=k/j;return(-b+this.sqrt(b*b-2*l*(k*k/(-2*j)-h+j/2+f-i/2)))/l+e};Voronoi.prototype.Beachsection.prototype.leftParabolicCut=function(a,b){if(this.sweep!==b||this.lid!==a.id){this.sweep=b;this.lid=a.id;this.lBreak=this._leftParabolicCut(this.site,a,b)}return this.lBreak};Voronoi.prototype.Beachsection.prototype.isCollapsing=function(){return this.circleEvent!==undefined&&this.circleEvent.type===Voronoi.prototype.CIRCLE_EVENT};Voronoi.prototype.Site=function(x,y){this.id=this.constructor.prototype.idgenerator++;this.x=x;this.y=y};Voronoi.prototype.Site.prototype.destroy=function(){this.id=0};Voronoi.prototype.Vertex=function(x,y){this.x=x;this.y=y};Voronoi.prototype.Edge=function(a,b){this.id=this.constructor.prototype.idgenerator++;this.lSite=a;this.rSite=b;this.va=this.vb=undefined};Voronoi.prototype.Halfedge=function(a,b){this.site=a;this.edge=b};Voronoi.prototype.Cell=function(a){this.site=a;this.halfedges=[]};Voronoi.prototype.Cells=function(){this.numCells=0};Voronoi.prototype.Cells.prototype.addCell=function(a){this[a.site.id]=a;this.numCells++};Voronoi.prototype.Cells.prototype.removeCell=function(a){delete this[a.site.id];this.numCells--};Voronoi.prototype.Site.prototype.idgenerator=1;Voronoi.prototype.Edge.prototype.isLineSegment=function(){return this.id!==0&&Boolean(this.va)&&Boolean(this.vb)};Voronoi.prototype.Edge.prototype.idgenerator=1;Voronoi.prototype.Halfedge.prototype.isLineSegment=function(){return this.edge.id!==0&&Boolean(this.edge.va)&&Boolean(this.edge.vb)};Voronoi.prototype.Halfedge.prototype.getStartpoint=function(){return this.edge.lSite.id==this.site.id?this.edge.va:this.edge.vb};Voronoi.prototype.Halfedge.prototype.getEndpoint=function(){return this.edge.lSite.id==this.site.id?this.edge.vb:this.edge.va};Voronoi.prototype.leftBreakPoint=function(a,b){var c=this.arcs[a];var d=c.site;if(d.y==b){return d.x}if(a===0){return-Infinity}return c.leftParabolicCut(this.arcs[a-1].site,b)};Voronoi.prototype.rightBreakPoint=function(a,b){if(a<this.arcs.length-1){return this.leftBreakPoint(a+1,b)}var c=this.arcs[a].site;return c.y==b?c.x:Infinity};Voronoi.prototype.findInsertionPoint=function(x,a){var n=this.arcs.length;if(!n){return 0}var l=0;var r=n;var i;while(l<r){i=(l+r)>>1;if(this.lessThanWithEpsilon(x,this.leftBreakPoint(i,a))){r=i;continue}if(this.greaterThanOrEqualWithEpsilon(x,this.rightBreakPoint(i,a))){l=i+1;continue}return i}return l};Voronoi.prototype.findDeletionPoint=function(x,a){var n=this.arcs.length;if(!n){return 0}var l=0;var r=n;var i;var b;while(l<r){i=(l+r)>>1;b=this.leftBreakPoint(i,a);if(this.lessThanWithEpsilon(x,b)){r=i;continue}if(this.greaterThanWithEpsilon(x,b)){l=i+1;continue}b=this.rightBreakPoint(i,a);if(this.greaterThanWithEpsilon(x,b)){l=i+1;continue}if(this.lessThanWithEpsilon(x,b)){r=i;continue}return i}};Voronoi.prototype.createEdge=function(a,b,c,d){var e=new this.Edge(a,b);this.edges.push(e);if(c!==undefined){this.setEdgeStartpoint(e,a,b,c)}if(d!==undefined){this.setEdgeEndpoint(e,a,b,d)}this.cells[a.id].halfedges.push(new this.Halfedge(a,e));this.cells[b.id].halfedges.push(new this.Halfedge(b,e));return e};Voronoi.prototype.createBorderEdge=function(a,b,c){var d=new this.Edge(a,null);d.va=b;d.vb=c;this.edges.push(d);return d};Voronoi.prototype.destroyEdge=function(a){a.id=0};Voronoi.prototype.setEdgeStartpoint=function(a,b,c,d){if(a.va===undefined&&a.vb===undefined){a.va=d;a.lSite=b;a.rSite=c}else if(a.lSite.id==c.id){a.vb=d}else{a.va=d}};Voronoi.prototype.setEdgeEndpoint=function(a,b,c,d){this.setEdgeStartpoint(a,c,b,d)};Voronoi.prototype.removeArc=function(a){var x=a.center.x;var y=a.center.y;var b=a.y;var c=this.findDeletionPoint(x,b);var d=c;while(d-1>0&&this.equalWithEpsilon(x,this.leftBreakPoint(d-1,b))){d--}var e=c;while(e+1<this.arcs.length&&this.equalWithEpsilon(x,this.rightBreakPoint(e+1,b))){e++}var f,rArc;for(var g=d;g<=e+1;g++){f=this.arcs[g-1];rArc=this.arcs[g];this.setEdgeStartpoint(rArc.edge,f.site,rArc.site,new this.Vertex(x,y))}this.voidCircleEvents(d-1,e+1);this.arcs.splice(d,e-d+1);f=this.arcs[d-1];rArc=this.arcs[d];rArc.edge=this.createEdge(f.site,rArc.site,undefined,new this.Vertex(x,y));this.addCircleEvents(d-1,b);this.addCircleEvents(d,b)};Voronoi.prototype.addArc=function(a){var b=new this.Beachsection(a);var c=this.findInsertionPoint(a.x,a.y);if(c==this.arcs.length){this.arcs.push(b);if(c===0){return}b.edge=this.createEdge(this.arcs[c-1].site,b.site);return}var d,rArc;if(c>0&&this.equalWithEpsilon(a.x,this.rightBreakPoint(c-1,a.y))&&this.equalWithEpsilon(a.x,this.leftBreakPoint(c,a.y))){d=this.arcs[c-1];rArc=this.arcs[c];this.voidCircleEvents(c-1,c);var e=this.circumcircle(d.site,a,rArc.site);this.setEdgeStartpoint(rArc.edge,d.site,rArc.site,new this.Vertex(e.x,e.y));b.edge=this.createEdge(d.site,b.site,undefined,new this.Vertex(e.x,e.y));rArc.edge=this.createEdge(b.site,rArc.site,undefined,new this.Vertex(e.x,e.y));this.arcs.splice(c,0,b);this.addCircleEvents(c-1,a.y);this.addCircleEvents(c+1,a.y);return}this.voidCircleEvents(c);d=this.arcs[c];rArc=new this.Beachsection(d.site);this.arcs.splice(c+1,0,b,rArc);b.edge=rArc.edge=this.createEdge(d.site,b.site);this.addCircleEvents(c,a.y);this.addCircleEvents(c+2,a.y)};Voronoi.prototype.circumcircle=function(a,b,c){var e=a.x;var f=a.y;var g=b.x-e;var h=b.y-f;var i=c.x-e;var j=c.y-f;var d=2*(g*j-h*i);var k=g*g+h*h;var l=i*i+j*j;var x=(j*k-h*l)/d;var y=(g*l-i*k)/d;return{x:x+e,y:y+f,radius:this.sqrt(x*x+y*y)}};Voronoi.prototype.addCircleEvents=function(a,b){if(a<=0||a>=this.arcs.length-1){return}var c=this.arcs[a];var d=this.arcs[a-1].site;var e=this.arcs[a].site;var f=this.arcs[a+1].site;if(d.id==f.id||d.id==e.id||e.id==f.id){return}if((d.y-e.y)*(f.x-e.x)<=(d.x-e.x)*(f.y-e.y)){return}var g=this.circumcircle(d,e,f);var h=g.y+g.radius;if(!this.greaterThanOrEqualWithEpsilon(h,b)){return}var i={type:this.CIRCLE_EVENT,site:e,x:g.x,y:h,center:{x:g.x,y:g.y}};c.circleEvent=i;this.queuePushCircle(i)};Voronoi.prototype.voidCircleEvents=function(a,b){if(b===undefined){b=a}a=this.max(a,0);b=this.min(b,this.arcs.length-1);while(a<=b){var c=this.arcs[a];if(c.circleEvent!==undefined){c.circleEvent.type=this.VOID_EVENT;c.circleEvent=undefined}a++}};Voronoi.prototype.queueSanitize=function(){var q=this.circEvents;var a=q.length;if(!a){return}var b=a;while(b&&q[b-1].type===this.VOID_EVENT){b--}var c=a-b;if(c){q.splice(b,c)}var d=this.arcs.length;if(q.length<d*2){return}while(true){a=b-1;while(a>0&&q[a-1].type!==this.VOID_EVENT){a--}if(a<=0){break}b=a-1;while(b>0&&q[b-1].type===this.VOID_EVENT){b--}c=a-b;q.splice(b,c);if(q.length<d){return}}};Voronoi.prototype.queuePop=function(){var a=this.siteEvents.length>0?this.siteEvents[this.siteEvents.length-1]:null;var b=this.circEvents.length>0?this.circEvents[this.circEvents.length-1]:null;if(Boolean(a)!==Boolean(b)){return a?this.siteEvents.pop():this.circEvents.pop()}if(!a){return null}if(a.y<b.y||(a.y==b.y&&a.x<b.x)){return this.siteEvents.pop()}return this.circEvents.pop()};Voronoi.prototype.queuePushSite=function(o){var q=this.siteEvents;var r=q.length;if(r){var l=0;var i,c;while(l<r){i=(l+r)>>1;c=o.y-q[i].y;if(!c){c=o.x-q[i].x}if(c>0){r=i}else if(c<0){l=i+1}else{return}}q.splice(l,0,o)}else{q.push(o)}};Voronoi.prototype.queuePushCircle=function(o){var q=this.circEvents;var r=q.length;if(r){var l=0;var i,c;while(l<r){i=(l+r)>>1;c=o.y-q[i].y;if(!c){c=o.x-q[i].x}if(c>0){r=i}else{l=i+1}}q.splice(l,0,o)}else{q.push(o)}};Voronoi.prototype.getBisector=function(a,b){var r={x:(a.x+b.x)/2,y:(a.y+b.y)/2};if(b.y==a.y){return r}r.m=(a.x-b.x)/(b.y-a.y);r.b=r.y-r.m*r.x;return r};Voronoi.prototype.connectEdge=function(a,b){var c=a.vb;if(!!c){return true}var d=a.va;var e=b.xl;var g=b.xr;var h=b.yt;var i=b.yb;var j=a.lSite;var k=a.rSite;var f=this.getBisector(j,k);if(f.m===undefined){if(f.x<e||f.x>=g){return false}if(j.x>k.x){if(d===undefined){d=new this.Vertex(f.x,h)}else if(d.y>=i){return false}c=new this.Vertex(f.x,i)}else{if(d===undefined){d=new this.Vertex(f.x,i)}else if(d.y<h){return false}c=new this.Vertex(f.x,h)}}else if(f.m<1){if(j.y<k.y){if(d===undefined){d=new this.Vertex(e,f.m*e+f.b)}else if(d.x>=g){return false}c=new this.Vertex(g,f.m*g+f.b)}else{if(d===undefined){d=new this.Vertex(g,f.m*g+f.b)}else if(d.x<e){return false}c=new this.Vertex(e,f.m*e+f.b)}}else{if(j.x>k.x){if(d===undefined){d=new this.Vertex((h-f.b)/f.m,h)}else if(d.y>=i){return false}c=new this.Vertex((i-f.b)/f.m,i)}else{if(d===undefined){d=new this.Vertex((i-f.b)/f.m,i)}else if(d.y<h){return false}c=new this.Vertex((h-f.b)/f.m,h)}}a.va=d;a.vb=c;return true};Voronoi.prototype.clipEdge=function(a,b){var c=a.va.x;var d=a.va.y;var e=a.vb.x;var f=a.vb.y;var g=0;var h=1;var i=e-c;var j=f-d;var q=c-b.xl;if(i===0&&q<0){return false}var r=-q/i;if(i<0){if(r<g){return false}else if(r<h){h=r}}else if(i>0){if(r>h){return false}else if(r>g){g=r}}q=b.xr-c;if(i===0&&q<0){return false}r=q/i;if(i<0){if(r>h){return false}else if(r>g){g=r}}else if(i>0){if(r<g){return false}else if(r<h){h=r}}q=d-b.yt;if(j===0&&q<0){return false}r=-q/j;if(j<0){if(r<g){return false}else if(r<h){h=r}}else if(j>0){if(r>h){return false}else if(r>g){g=r}}q=b.yb-d;if(j===0&&q<0){return false}r=q/j;if(j<0){if(r>h){return false}else if(r>g){g=r}}else if(j>0){if(r<g){return false}else if(r<h){h=r}}a.va.x=c+g*i;a.va.y=d+g*j;a.vb.x=c+h*i;a.vb.y=d+h*j;return true};Voronoi.prototype.clipEdges=function(a){var b=this.edges;var c=b.length;var d;for(var e=c-1;e>=0;e-=1){d=b[e];if(!this.connectEdge(d,a)||!this.clipEdge(d,a)||this.verticesAreEqual(d.va,d.vb)){this.destroyEdge(d);b.splice(e,1)}}};Voronoi.prototype.verticesAreEqual=function(a,b){return this.equalWithEpsilon(a.x,b.x)&&this.equalWithEpsilon(a.y,b.y)};Voronoi.prototype.sortHalfedgesCallback=function(a,b){var c=a.getStartpoint();var d=a.getEndpoint();var e=b.getStartpoint();var f=b.getEndpoint();return Math.atan2(f.y-e.y,f.x-e.x)-Math.atan2(d.y-c.y,d.x-c.x)};Voronoi.prototype.closeCells=function(a){var b=a.xl;var c=a.xr;var d=a.yt;var e=a.yb;this.clipEdges(a);var f=this.cells;var g;var h,iRight;var i,nHalfedges;var j;var k,endpoint;var l,vb;for(var m in f){g=f[m];if(!(g instanceof this.Cell)){continue}i=g.halfedges;h=i.length;while(h){iRight=h;while(iRight>0&&i[iRight-1].isLineSegment()){iRight--}h=iRight;while(h>0&&!i[h-1].isLineSegment()){h--}if(h===iRight){break}i.splice(h,iRight-h)}if(i.length===0){f.removeCell(g);continue}i.sort(this.sortHalfedgesCallback);nHalfedges=i.length;h=0;while(h<nHalfedges){iRight=(h+1)%nHalfedges;endpoint=i[h].getEndpoint();k=i[iRight].getStartpoint();if(!this.verticesAreEqual(endpoint,k)){l=new this.Vertex(endpoint.x,endpoint.y);if(this.equalWithEpsilon(endpoint.x,b)&&this.lessThanWithEpsilon(endpoint.y,e)){vb=new this.Vertex(b,this.equalWithEpsilon(k.x,b)?k.y:e)}else if(this.equalWithEpsilon(endpoint.y,e)&&this.lessThanWithEpsilon(endpoint.x,c)){vb=new this.Vertex(this.equalWithEpsilon(k.y,e)?k.x:c,e)}else if(this.equalWithEpsilon(endpoint.x,c)&&this.greaterThanWithEpsilon(endpoint.y,d)){vb=new this.Vertex(c,this.equalWithEpsilon(k.x,c)?k.y:d)}else if(this.equalWithEpsilon(endpoint.y,d)&&this.greaterThanWithEpsilon(endpoint.x,b)){vb=new this.Vertex(this.equalWithEpsilon(k.y,d)?k.x:b,d)}j=this.createBorderEdge(g.site,l,vb);i.splice(h+1,0,new this.Halfedge(g.site,j));nHalfedges=i.length}h++}}};Voronoi.prototype.addSites=function(a){var b=a.length;var v;for(var c=0;c<b;c++){v=a[c];this.sites.push(new this.Site(v.x,v.y))}};Voronoi.prototype.setSites=function(a){this.sites=[];this.addSites(a)};Voronoi.prototype.getSites=function(){return this.sites};Voronoi.prototype.compute=function(a){var b=new Date();this.siteEvents=[];this.circEvents=[];var c=this.sites.length;var d;for(var e=c-1;e>=0;e--){d=this.sites[e];if(!d.id){this.sites.splice(e,1)}else{this.queuePushSite({type:this.SITE_EVENT,x:d.x,y:d.y,site:d})}}this.arcs=[];this.edges=[];this.cells=new this.Cells();var f=this.queuePop();while(f){if(f.type===this.SITE_EVENT){this.cells.addCell(new this.Cell(f.site));this.addArc(f.site)}else if(f.type===this.CIRCLE_EVENT){this.removeArc(f)}else{this.queueSanitize()}f=this.queuePop()}this.closeCells(a);var g=new Date();var h={sites:this.sites,cells:this.cells,edges:this.edges,execTime:g.getTime()-b.getTime()};this.arcs=[];this.edges=[];this.cells=new this.Cells();return h};
+
+module.exports = function()
+{
+ return new Voronoi();
+}
46 node_modules/canvas/examples/spark.js
@@ -0,0 +1,46 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(40, 15)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+Object.defineProperty(Array.prototype, 'max', {
+ get: function(){
+ var max = 0;
+ for (var i = 0, len = this.length; i < len; ++i) {
+ var n = this[i];
+ if (n > max) max = n;
+ }
+ return max;
+ }
+});
+
+function spark(ctx, data) {
+ var len = data.length
+ , pad = 1
+ , width = ctx.canvas.width
+ , height = ctx.canvas.height
+ , barWidth = width / len
+ , max = data.max;
+ ctx.fillStyle = 'rgba(0,0,255,0.5)';
+ ctx.strokeStyle = 'red';
+ ctx.lineWidth = 1;
+ data.forEach(function(n, i){
+ var x = i * barWidth + pad
+ , y = height * (n / max)
+ ctx.lineTo(x, height - y);
+ ctx.fillRect(x, height, barWidth - pad, -y);
+ });
+ ctx.stroke();
+}
+
+spark(ctx, [1,2,4,5,10,4,2,5,4,3,3,2]);
+
+canvas.toBuffer(function(err, buf){
+ if (err) throw err;
+ fs.writeFile(__dirname + '/spark.png', buf);
+});
33 node_modules/canvas/examples/state.js
@@ -0,0 +1,33 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(150, 150)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+ctx.fillRect(0,0,150,150); // Draw a rectangle with default settings
+ctx.save(); // Save the default state
+
+ctx.fillStyle = '#09F' // Make changes to the settings
+ctx.fillRect(15,15,120,120); // Draw a rectangle with new settings
+
+ctx.save(); // Save the current state
+ctx.fillStyle = '#FFF' // Make changes to the settings
+ctx.globalAlpha = 0.5;
+ctx.fillRect(30,30,90,90); // Draw a rectangle with new settings
+
+ctx.restore(); // Restore previous state
+ctx.fillRect(45,45,60,60); // Draw a rectangle with restored settings
+
+ctx.restore(); // Restore original state
+ctx.fillRect(60,60,30,30); // Draw a rectangle with restored settings
+
+var out = fs.createWriteStream(__dirname + '/state.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
41 node_modules/canvas/examples/text.js
@@ -0,0 +1,41 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(200, 200)
+ , ctx = canvas.getContext('2d')
+ , fs = require('fs');
+
+ctx.globalAlpha = .2;
+
+ctx.strokeRect(0,0,200,200);
+ctx.lineTo(0,100);
+ctx.lineTo(200,100);
+ctx.stroke();
+
+ctx.beginPath();
+ctx.lineTo(100,0);
+ctx.lineTo(100,200);
+ctx.stroke();
+
+ctx.globalAlpha = 1;
+ctx.font = 'normal 40px Impact, serif';
+
+ctx.rotate(.5);
+ctx.translate(20,-40);
+
+ctx.lineWidth = 1;
+ctx.strokeStyle = '#ddd';
+ctx.strokeText("Wahoo", 50, 100);
+
+ctx.fillStyle = '#000';
+ctx.fillText("Wahoo", 49, 99);
+
+var out = fs.createWriteStream(__dirname + '/text.png')
+ , stream = canvas.createPNGStream();
+
+stream.on('data', function(chunk){
+ out.write(chunk);
+});
140 node_modules/canvas/examples/voronoi.js
@@ -0,0 +1,140 @@
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('../lib/canvas')
+ , canvas = new Canvas(1920, 1200)
+ , ctx = canvas.getContext('2d')
+ , http = require('http')
+ , fs = require('fs');
+
+var voronoiFactory = require('./rhill-voronoi-core-min.js');
+
+http.createServer(function (req, res) {
+ var voronoi = voronoiFactory()
+ , start = new Date;
+ var bbox = { xl: 0, xr: canvas.width, yt: 0, yb: canvas.height };
+
+ for (var i =0 ;i<340;i++)
+ {
+ var x = Math.random()*canvas.width;
+ var y = Math.random()*canvas.height;
+ voronoi.addSites([{x:x,y:y}]);
+ };
+ var diagram = voronoi.compute(bbox);
+
+ ctx.beginPath();
+ ctx.rect(0,0,canvas.width,canvas.height);
+ ctx.fillStyle = '#fff';
+ ctx.fill();
+ ctx.strokeStyle = 'black';
+ ctx.stroke();
+ // voronoi
+ ctx.strokeStyle='rgba(255,255,255,0.5)';
+ ctx.lineWidth = 4;
+ // edges
+ var edges = diagram.edges;
+ var nEdges = edges.length;
+
+ var sites = diagram.sites;
+ var nSites = sites.length;
+ for (var iSite=nSites-1; iSite>=0; iSite-=1)
+ {
+ site = sites[iSite];
+ ctx.rect(site.x-0.5,site.y-0.5,1,1);
+
+
+
+// ctx.stroke();
+ var cell = diagram.cells[diagram.sites[iSite].id];
+ if (cell !== undefined)
+ {
+ var halfedges = cell.halfedges;
+ var nHalfedges = halfedges.length;
+ if (nHalfedges < 3) {return;}
+ var minx = canvas.width;
+ var miny = canvas.height;
+ var maxx = 0;
+ var maxy = 0;
+
+ var v = halfedges[0].getStartpoint();
+ ctx.beginPath();
+ ctx.moveTo(v.x,v.y);
+
+ for (var iHalfedge=0; iHalfedge<nHalfedges; iHalfedge++)
+ {
+ v = halfedges[iHalfedge].getEndpoint();
+ ctx.lineTo(v.x,v.y);
+ if (v.x< minx) minx = v.x;
+ if (v.y< miny) miny = v.y;
+ if (v.x> maxx) maxx = v.x;
+ if (v.y> maxy) maxy = v.y;
+ }
+ var C = Math.floor(Math.random()*128 + 127).toString();
+
+
+ var midx = (maxx+minx)/2;
+ var midy = (maxy+miny)/2;
+ var R = 0;
+
+ for (var iHalfedge=0; iHalfedge<nHalfedges; iHalfedge++)
+ {
+ v = halfedges[iHalfedge].getEndpoint();
+ var dx = v.x - site.x;
+ var dy = v.y - site.y;
+ var newR = Math.sqrt(dx*dx + dy*dy);
+ if (newR >R) R = newR;
+ }
+ midx = site.x;
+ midy = site.y;
+ var radgrad = ctx.createRadialGradient(midx+R*0.3,midy-R*0.3,0,midx,midy,R);
+ radgrad.addColorStop(0, "#09760b");
+ radgrad.addColorStop(1.0, "black");
+
+
+ ctx.fillStyle = radgrad;
+ ctx.fill();
+
+ var radgrad2 = ctx.createRadialGradient(midx-R*0.5,midy+R*0.5,R*0.1,midx,midy,R);
+ radgrad2.addColorStop(0, "rgba(255,255,255,0.5)");
+ radgrad2.addColorStop(0.04, "rgba(255,255,255,0.3)");
+ radgrad2.addColorStop(0.05, "rgba(255,255,255,0)");
+
+
+ ctx.fillStyle = radgrad2;
+ ctx.fill();
+
+ var lingrad = ctx.createLinearGradient(minx, site.y, minx+100, site.y-20);
+ lingrad.addColorStop(0.0, "rgba(255,255,255,0.5)");
+ lingrad.addColorStop(0.2, "rgba(255,255,255,0.2)");
+ lingrad.addColorStop(1.0, "rgba(255,255,255,0)");
+ ctx.fillStyle = lingrad;
+ ctx.fill();
+
+ }
+
+ }
+
+ if (nEdges)
+ {
+ var edge, v;
+ ctx.beginPath();
+ for (var iEdge=nEdges-1; iEdge>=0; iEdge-=1) {
+ edge = edges[iEdge];
+ v = edge.va;
+ ctx.moveTo(v.x,v.y);
+ v = edge.vb;
+ ctx.lineTo(v.x,v.y);
+ }
+ ctx.stroke();
+ }
+
+ canvas.toBuffer(function(err, buf){
+ var duration = new Date - start;
+ console.log('Rendered in %dms', duration);
+ res.writeHead(200, { 'Content-Type': 'image/png', 'Content-Length': buf.length });
+ res.end(buf);
+ });
+}).listen(3000);
+console.log('Server running on port 3000');
1  node_modules/canvas/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/canvas');
48 node_modules/canvas/install
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+PKG_CONFIG="http://pkgconfig.freedesktop.org/releases/pkg-config-0.23.tar.gz"
+PIXMAN="http://www.cairographics.org/releases/pixman-0.20.2.tar.gz"
+CAIRO="http://cairographics.org/releases/cairo-1.10.2.tar.gz"
+LIBPNG="ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.2.40.tar.gz"
+PREFIX=${1-/usr/local}
+
+require() {
+ echo "... checking for $1"
+ if test `which $1`; then
+ echo "... found"
+ else
+ echo "... not found"
+ exit 1
+ fi
+}
+
+fetch() {
+ local tarball=`basename $1`
+ echo "... downloading $tarball"
+ local dir=${tarball/.tar.gz/}
+ curl -# -L $1 -o $tarball \
+ && echo "... unpacking" \
+ && tar -zxf $tarball \
+ && echo "... removing tarball" \
+ && rm -fr $tarball \
+ && install $dir
+}
+
+install() {
+ local dir=$1
+ echo "... installing $1"
+ cd $dir \
+ && ./configure --disable-dependency-tracking --prefix=$PREFIX \
+ && make \
+ && make install \
+ && echo "... removing $dir" \
+ && cd .. && rm -fr $dir
+}
+
+echo "... installing to $PREFIX"
+require curl
+require tar
+test `which pkg-config` || fetch $PKG_CONFIG
+require 'pkg-config'
+fetch $PIXMAN
+fetch $CAIRO
10 node_modules/canvas/lib/bindings.js
@@ -0,0 +1,10 @@
+/**
+ * Compat for changes from node 0.4.x to 0.6.x.
+ */
+try {
+ module.exports = require('../build/Release/canvas');
+} catch (e) { try {
+ module.exports = require('../build/default/canvas');
+} catch (e) {
+ throw e;
+}}
146 node_modules/canvas/lib/canvas.js
@@ -0,0 +1,146 @@
+
+/*!
+ * Canvas
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var canvas = require('./bindings')
+ , Canvas = canvas.Canvas
+ , Image = canvas.Image
+ , cairoVersion = canvas.cairoVersion
+ , PixelArray = canvas.PixelArray
+ , Context2d = require('./context2d')
+ , PNGStream = require('./pngstream')
+ , fs = require('fs');
+
+/**
+ * Export `Canvas` as the module.
+ */
+
+var Canvas = exports = module.exports = Canvas;
+
+/**
+ * Library version.
+ */
+
+exports.version = '0.8.1';
+
+/**
+ * Cairo version.
+ */
+
+exports.cairoVersion = cairoVersion;
+
+/**
+ * Expose constructors.
+ */
+
+exports.Context2d = Context2d;
+exports.PNGStream = PNGStream;
+exports.PixelArray = PixelArray;
+exports.Image = Image;
+
+/**
+ * Context2d implementation.
+ */
+
+require('./context2d');
+
+/**
+ * Image implementation.
+ */
+
+require('./image');
+
+/**
+ * PixelArray implementation.
+ */
+
+require('./pixelarray');
+
+/**
+ * Inspect canvas.
+ *
+ * @return {String}
+ * @api public
+ */
+
+Canvas.prototype.inspect = function(){
+ return '[Canvas ' + this.width + 'x' + this.height + ']';
+};
+
+/**
+ * Get a context object.
+ *
+ * @param {String} contextId
+ * @return {Context2d}
+ * @api public
+ */
+
+Canvas.prototype.getContext = function(contextId){
+ if ('2d' == contextId) {
+ var ctx = this._context2d || (this._context2d = new Context2d(this));
+ this.context = ctx;
+ ctx.canvas = this;
+ return ctx;
+ }
+};
+
+/**
+ * Create a `PNGStream` for `this` canvas.
+ *
+ * @return {PNGStream}
+ * @api public
+ */
+
+Canvas.prototype.createPNGStream = function(){
+ return new PNGStream(this);
+};
+
+/**
+ * Create a synchronous `PNGStream` for `this` canvas.
+ *
+ * @return {PNGStream}
+ * @api public
+ */
+
+Canvas.prototype.createSyncPNGStream = function(){
+ return new PNGStream(this, true);
+};
+
+/**
+ * Return a data url. Pass a function for async support.
+ *
+ * @param {String|Function} type
+ * @param {Function} fn
+ * @return {String}
+ * @api public
+ */
+
+Canvas.prototype.toDataURL = function(type, fn){
+ // Default to png
+ type = type || 'image/png';
+
+ // Allow callback as first arg
+ if ('function' == typeof type) fn = type, type = 'image/png';
+
+ // Throw on non-png
+ if ('image/png' != type) throw new Error('currently only image/png is supported');
+
+ var prefix = 'data:' + type + ';base64,';
+
+ if (fn) {
+ this.toBuffer(function(err, buf){
+ if (err) return fn(err);
+ var str = 'data:' + type
+ fn(null, prefix + buf.toString('base64'));
+ });
+ } else {
+ return prefix + this.toBuffer().toString('base64');
+ }
+};
323 node_modules/canvas/lib/context2d.js
@@ -0,0 +1,323 @@
+
+/*!
+ * Canvas - Context2d
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var canvas = require('./bindings')
+ , Context2d = canvas.CanvasRenderingContext2d
+ , CanvasGradient = canvas.CanvasGradient
+ , ImageData = canvas.ImageData
+ , PixelArray = canvas.CanvasPixelArray;
+
+/**
+ * Export `Context2d` as the module.
+ */
+
+var Context2d = exports = module.exports = Context2d;
+
+/**
+ * Cache color string RGBA values.
+ */
+
+var cache = {};
+
+/**
+ * Text baselines.
+ */
+
+var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging'];
+
+/**
+ * Font RegExp helpers.
+ */
+
+var weights = 'normal|bold|bolder|lighter|[1-9]00'
+ , styles = 'normal|italic|oblique'
+ , units = 'px|pt|pc|in|cm|mm|%'
+ , string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+';
+
+/**
+ * Font parser RegExp;
+ */
+
+var fontre = new RegExp('^ *'
+ + '(?:(' + weights + ') *)?'
+ + '(?:(' + styles + ') *)?'
+ + '([\\d\\.]+)(' + units + ') *'
+ + '((?:' + string + ')( *, *(?:' + string + '))*)'
+ );
+
+/**
+ * Parse font `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+var parseFont = exports.parseFont = function(str){
+ var font = {}
+ , captures = fontre.exec(str);
+
+ // Invalid
+ if (!captures) return;
+
+ // Cached
+ if (cache[str]) return cache[str];
+
+ // Populate font object
+ font.weight = captures[1] || 'normal';
+ font.style = captures[2] || 'normal';
+ font.size = parseFloat(captures[3]);
+ font.unit = captures[4];
+ font.family = captures[5].replace(/["']/g, '');
+
+ // TODO: dpi
+ // TODO: remaining unit conversion
+ switch (font.unit) {
+ case 'pt':
+ font.size /= .75;
+ break;
+ case 'in':
+ font.size *= 96;
+ break;
+ case 'mm':
+ font.size *= 96.0 / 25.4;
+ break;
+ case 'cm':
+ font.size *= 96.0 / 2.54;
+ break;
+ }
+
+ return cache[str] = font;
+};
+
+/**
+ * Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`.
+ *
+ * @param {Number} x0
+ * @param {Number} y0
+ * @param {Number} x1
+ * @param {Number} y1
+ * @return {CanvasGradient}
+ * @api public
+ */
+
+Context2d.prototype.createLinearGradient = function(x0, y0, x1, y1){
+ return new CanvasGradient(x0, y0, x1, y1);
+};
+
+/**
+ * Create a radial gradient at the given point `(x0, y0)` and `(x1, y1)`
+ * and radius `r0` and `r1`.
+ *
+ * @param {Number} x0
+ * @param {Number} y0
+ * @param {Number} r0
+ * @param {Number} x1
+ * @param {Number} y1
+ * @param {Number} r1
+ * @return {CanvasGradient}
+ * @api public
+ */
+
+Context2d.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){
+ return new CanvasGradient(x0, y0, r0, x1, y1, r1);
+};
+
+/**
+ * Reset transform matrix to identity, then apply the given args.
+ *
+ * @param {...}
+ * @api public
+ */
+
+Context2d.prototype.setTransform = function(){
+ this.resetTransform();
+ this.transform.apply(this, arguments);
+};
+
+/**
+ * Set the fill style with the given css color string.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineSetter__('fillStyle', function(val){
+ if (val instanceof CanvasGradient) {
+ this.lastFillStyle = val;
+ this._setFillPattern(val);
+ } else if ('string' == typeof val) {
+ this._setFillColor(val);
+ }
+});
+
+/**
+ * Get previous fill style.
+ *
+ * @return {CanvasGradient|String}
+ * @api public
+ */
+
+Context2d.prototype.__defineGetter__('fillStyle', function(){
+ return this.lastFillStyle || this.fillColor;
+});
+
+/**
+ * Set the stroke style with the given css color string.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineSetter__('strokeStyle', function(val){
+ if (val instanceof CanvasGradient) {
+ this.lastStrokeStyle = val;
+ this._setStrokePattern(val);
+ } else if ('string' == typeof val) {
+ this._setStrokeColor(val);
+ }
+});
+
+/**
+ * Get previous stroke style.
+ *
+ * @return {CanvasGradient|String}
+ * @api public
+ */
+
+Context2d.prototype.__defineGetter__('strokeStyle', function(){
+ return this.lastStrokeStyle || this.strokeColor;
+});
+
+
+/**
+ * Set font.
+ *
+ * @see exports.parseFont()
+ * @api public
+ */
+
+Context2d.prototype.__defineSetter__('font', function(val){
+ if ('string' == typeof val) {
+ var font;
+ if (font = parseFont(val)) {
+ this.lastFontString = val;
+ this._setFont(
+ font.weight
+ , font.style
+ , font.size
+ , font.unit
+ , font.family);
+ }
+ }
+});
+
+/**
+ * Get the current font.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineGetter__('font', function(){
+ return this.lastFontString || '10px sans-serif';
+});
+
+/**
+ * Set text baseline.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineSetter__('textBaseline', function(val){
+ var n = baselines.indexOf(val);
+ if (~n) {
+ this.lastBaseline = val;
+ this._setTextBaseline(n);
+ }
+});
+
+/**
+ * Get the current baseline setting.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineGetter__('textBaseline', function(){
+ return this.lastBaseline || 'alphabetic';
+});
+
+/**
+ * Set text alignment.
+ *
+ * @api public
+ */
+
+Context2d.prototype.__defineSetter__('textAlign', function(val){
+ switch (val) {
+ case 'center':
+ this._setTextAlignment(0);
+ this.lastTextAlignment = val;
+ break;
+ case 'left':
+ case 'start':
+ this._setTextAlignment(-1);
+ this.lastTextAlignment = val;
+ break;
+ case 'right':
+ case 'end':
+ this._setTextAlignment(1);
+ this.lastTextAlignment = val;
+ break;
+ }
+});
+
+/**
+ * Get the current font.
+ *
+ * @see exports.parseFont()
+ * @api public
+ */
+
+Context2d.prototype.__defineGetter__('textAlign', function(){
+ return this.lastTextAlignment || 'start';
+});
+
+/**
+ * Get `ImageData` with the given rect.
+ *
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} width
+ * @param {Number} height
+ * @return {ImageData}
+ * @api public
+ */
+
+Context2d.prototype.getImageData = function(x, y, width, height){
+ var arr = new PixelArray(this.canvas, x, y, width, height);
+ return new ImageData(arr);
+};
+
+/**
+ * Create `ImageData` with the given dimensions or
+ * `ImageData` instance for dimensions.
+ *
+ * @param {Number|ImageData} width
+ * @param {Number} height
+ * @return {ImageData}
+ * @api public
+ */
+
+Context2d.prototype.createImageData = function(width, height){
+ if (width instanceof ImageData) {
+ height = width.height;
+ width = width.width;
+ }
+ return new ImageData(new PixelArray(width, height));
+};
60 node_modules/canvas/lib/image.js
@@ -0,0 +1,60 @@
+
+/*!
+ * Canvas - Image
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Canvas = require('./bindings')
+ , Image = Canvas.Image;
+
+/**
+ * Src setter.
+ *
+ * - convert data uri to `Buffer`
+ *
+ * @param {String|Buffer} val filename, buffer, data uri
+ * @api public
+ */
+
+Image.prototype.__defineSetter__('src', function(val){
+ if ('string' == typeof val && 0 == val.indexOf('data:')) {
+ val = val.slice(val.indexOf(',') + 1);
+ this.source = new Buffer(val, 'base64');
+ } else {
+ this.source = val;
+ }
+});
+
+/**
+ * Src getter.
+ *
+ * TODO: return buffer
+ *
+ * @api public
+ */
+
+Image.prototype.__defineGetter__('src', function(){
+ return this.source;
+});
+
+/**
+ * Inspect image.
+ *
+ * TODO: indicate that the .src was a buffer, data uri etc
+ *
+ * @return {String}
+ * @api public
+ */
+
+Image.prototype.inspect = function(){
+ return '[Image'
+ + (this.complete ? ':' + this.width + 'x' + this.height : '')
+ + (this.src ? ' ' + this.src : '')
+ + (this.complete ? ' complete' : '')
+ + ']';