diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..a27a84a
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,5 @@
+{
+ "node":true,
+ "browser": true,
+ "expr": true
+}
\ No newline at end of file
diff --git a/examples/custom-draw/app.js b/examples/custom-draw/app.js
new file mode 100644
index 0000000..935df15
--- /dev/null
+++ b/examples/custom-draw/app.js
@@ -0,0 +1,92 @@
+/** @jsx React.DOM */
+
+'use strict';
+
+var React = require('react');
+var ReactCanvas = require('react-canvas');
+
+var Surface = ReactCanvas.Surface;
+var Group = ReactCanvas.Group;
+
+
+ReactCanvas.registerLayerType('circle', function (ctx, layer) {
+ var x = layer.frame.x;
+ var y = layer.frame.y;
+ var width = layer.frame.width;
+ var height = layer.frame.height;
+ var centerX = x + width / 2;
+ var centerY = y + height / 2;
+
+ var fillColor = layer.backgroundColor || '#FFF';
+ var strokeColor = layer.borderColor || '#FFF';
+ var strokeWidth = layer.borderWidth || 0;
+
+ var shadowColor = layer.shadowColor || 0;
+ var shadowOffsetX = layer.shadowOffsetX || 0;
+ var shadowOffsetY = layer.shadowOffsetY || 0;
+ var shadowBlur = layer.shadowBlur || 0;
+
+ var radius = Math.min(width / 2, height / 2) - Math.ceil(strokeWidth / 2);
+
+
+
+ ctx.beginPath();
+ ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
+ if (shadowOffsetX || shadowOffsetY) {
+ ctx.shadowColor = shadowColor;
+ ctx.shadowBlur = shadowBlur;
+ ctx.shadowOffsetX = shadowOffsetX;
+ ctx.shadowOffsetY = shadowOffsetY;
+ }
+
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ if (strokeWidth > 0) {
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = strokeColor;
+ ctx.stroke();
+ }
+});
+
+var Circle = ReactCanvas.createCanvasComponent({
+ displayName: 'Circle',
+ layerType: 'circle',
+
+ applyCustomProps: function (prevProps, props) {
+ var style = props.style || {};
+ var layer = this.node;
+ layer.shadowColor = style.shadowColor || 0;
+ layer.shadowOffsetX = style.shadowOffsetX || 0;
+ layer.shadowOffsetY = style.shadowOffsetY || 0;
+ layer.shadowBlur = style.shadowBlur || 0;
+ }
+});
+
+
+
+var App = React.createClass({
+
+ render: function () {
+ return (
+
+
+
+ );
+ },
+
+});
+
+React.render(, document.getElementById('main'));
diff --git a/examples/custom-draw/index.html b/examples/custom-draw/index.html
new file mode 100644
index 0000000..71b6817
--- /dev/null
+++ b/examples/custom-draw/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ ReactCanvas: ListView
+
+
+
+
+
+
+
+
+
diff --git a/lib/DrawingUtils.js b/lib/DrawingUtils.js
index e2db275..d6e84fb 100644
--- a/lib/DrawingUtils.js
+++ b/lib/DrawingUtils.js
@@ -7,6 +7,40 @@ var FrameUtils = require('./FrameUtils');
var CanvasUtils = require('./CanvasUtils');
var Canvas = require('./Canvas');
+// Global map of layer type to drawFunction
+var _layerTypesToDrawFunction = {
+ 'image': drawImageRenderLayer,
+ 'text': drawTextRenderLayer,
+ 'gradient': drawGradientRenderLayer
+};
+
+/**
+ * Retrieve a draw function for the given layer type
+ * return the default `drawBaseRenderLayer` function if this type is not registered
+ *
+ * @param {String} type the layer type
+ * @return {Function} the function responsible for drawing the layer
+ */
+function getDrawFunction(type) {
+ return _layerTypesToDrawFunction.hasOwnProperty(type) ?
+ _layerTypesToDrawFunction[type] :
+ drawBaseRenderLayer;
+}
+
+/**
+ * Register a new layer type and the associated draw function
+ *
+ * @param {String} type the layer type
+ * @param {Function} drawFunction the function responsible for drawing the layer
+ */
+function registerLayerType(type, drawFunction) {
+ if (_layerTypesToDrawFunction.hasOwnProperty(type)) {
+ throw new Error('type `' + type + '` is already registered.');
+ }
+ _layerTypesToDrawFunction[type] = drawFunction;
+}
+
+
// Global backing store