1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
  4 //            Portions ©2010-2011 Strobe Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 sc_require('render_delegates/render_delegate');
  9 
 10 /**
 11   @class
 12   Renders and updates DOM representations of an image.
 13 
 14   Parameters
 15   --------------------------
 16   Expects these properties on the data source:
 17 
 18   - image: An Image object which has completed loading
 19 
 20   If any of these are not present in the data source, the render delegate
 21   will throw an error.
 22 
 23   Optional Parameters:
 24   ---------------------------
 25   If present, these properties will be used.
 26 
 27   - width: Used on the canvas element. If not provided, 0 is used and the canvas
 28             will not be visible.
 29   - height: Used on the canvas element. If not provided, 0 is used and the canvas
 30             will not be visible.
 31   - scale: If provided, the image will maintain aspect ratio as specified by this
 32           property. One of
 33             - SC.SCALE_NONE
 34             - SC.FILL
 35             - SC.BEST_FILL
 36             - SC.BEST_FIT
 37             - SC.BEST_FIT_DOWN_ONLY
 38             - percentage {Number}
 39           If not provided, SC.FILL will be the default (ie. expected image behaviour)
 40   - align: If provided, the image will align itself within its frame.  One of
 41             - SC.ALIGN_CENTER
 42             - SC.ALIGN_TOP_LEFT
 43             - SC.ALIGN_TOP
 44             - SC.ALIGN_TOP_RIGHT
 45             - SC.ALIGN_RIGHT
 46             - SC.ALIGN_BOTTOM_RIGHT
 47             - SC.ALIGN_BOTTOM
 48             - SC.ALIGN_BOTTOM_LEFT
 49             - SC.ALIGN_LEFT
 50   - backgroundColor: If provided, the canvas will render a backgroundColor
 51 */
 52 
 53 SC.BaseTheme.canvasImageRenderDelegate = SC.RenderDelegate.create({
 54   className: 'canvasImage',
 55 
 56   /** @private
 57     We don't have an element yet, so we do the minimal necessary setup
 58     here.
 59   */
 60   render: function (dataSource, context) {
 61     var width = dataSource.get('width') || 0,
 62         height = dataSource.get('height') || 0,
 63         type = dataSource.get('type') || SC.IMAGE_TYPE_URL,
 64         value = dataSource.get('value');
 65 
 66     // Support for CSS sprites (TODO: Remove this)
 67     if (value && type === SC.IMAGE_TYPE_CSS_CLASS) {
 68       context.addClass(value);
 69       dataSource.renderState._last_class = value;
 70     }
 71 
 72     context.setAttr('width', width);
 73     context.setAttr('height', height);
 74   },
 75 
 76   update: function (dataSource, jquery) {
 77     var elem = jquery[0],
 78         image = dataSource.get('image'),
 79         frame = dataSource.get('frame'),
 80         frameWidth = frame.width,
 81         frameHeight = frame.height,
 82         innerFrame = dataSource.get('innerFrame'),
 83         backgroundColor = dataSource.get('backgroundColor'),
 84         renderState = dataSource.get('renderState'),
 85         context,
 86         lastClass = dataSource.renderState._last_class,
 87         type = dataSource.get('type') || SC.IMAGE_TYPE_URL,
 88         value = dataSource.get('value');
 89 
 90     // Support for CSS sprites
 91     if (lastClass) jquery.removeClass(lastClass);
 92     if (value && type === SC.IMAGE_TYPE_CSS_CLASS) {
 93       jquery.addClass(value);
 94       dataSource.renderState._last_class = value;
 95 
 96       // Clear the context in case there was a URL previously
 97       if (elem && elem.getContext) {
 98         context = elem.getContext('2d');
 99         context.clearRect(0, 0, frameWidth, frameHeight);
100       }
101     } else {
102 
103       // We only care about specific values, check specifically for what matters
104       var innerFrameDidChange = ![innerFrame.x, innerFrame.y, innerFrame.width, innerFrame.height].isEqual(renderState._lastInnerFrameValues),
105           elemSizeDidChange = ![elem.width, elem.height].isEqual(renderState._lastElemSizeValues),
106           backgroundDidChange = dataSource.didChangeFor('canvasImageRenderDelegate', 'backgroundColor'),
107           imageDidChange = dataSource.didChangeFor('canvasImageRenderDelegate', 'image') || (image && image.complete) !== renderState._lastImageComplete;
108 
109       if (elemSizeDidChange || innerFrameDidChange || backgroundDidChange || imageDidChange) {
110 
111         if (elem && elem.getContext) {
112           elem.height = frameHeight;
113           elem.width = frameWidth;
114 
115           context = elem.getContext('2d');
116 
117           context.clearRect(0, 0, frameWidth, frameHeight);
118 
119           if (backgroundColor) {
120             context.fillStyle = backgroundColor;
121             context.fillRect(0, 0, frameWidth, frameHeight);
122           }
123 
124           if (image && image.complete) {
125             context.drawImage(image, Math.floor(innerFrame.x), Math.floor(innerFrame.y), Math.floor(innerFrame.width), Math.floor(innerFrame.height));
126           }
127         }
128 
129         // Update caches
130         renderState._lastInnerFrameValues = [innerFrame.x, innerFrame.y, innerFrame.width, innerFrame.height];
131         renderState._lastElemSizeValues = [elem.width, elem.height];
132         renderState._lastImageComplete = image && image.complete;
133       }
134     }
135   }
136 
137 });
138