├── .gitignore ├── src └── fabric │ ├── pencil_brush.coffee │ ├── canvas_with_viewport.coffee │ ├── viewport.coffee │ └── controls_extension │ └── object.coffee ├── Cakefile ├── LICENSE ├── README.md ├── example └── index.html └── dist └── fabricjs_viewport.js /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/* -------------------------------------------------------------------------------- /src/fabric/pencil_brush.coffee: -------------------------------------------------------------------------------- 1 | old = fabric.PencilBrush.prototype._render 2 | 3 | fabric.PencilBrush.prototype._render = () -> 4 | if @canvas.viewport 5 | ctx = this.canvas.contextTop 6 | ctx.save() 7 | ctx.scale(@canvas.viewport.zoom, @canvas.viewport.zoom) 8 | ctx.translate(@canvas.viewport.translate().x, @canvas.viewport.translate().y) 9 | old.apply(this) 10 | ctx.restore() 11 | else 12 | old.apply(this) 13 | -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | {exec} = require 'child_process' 3 | 4 | appFiles = [ 5 | 'fabric/controls_extension/object' 6 | 'fabric/viewport' 7 | 'fabric/pencil_brush' 8 | 'fabric/canvas_with_viewport' 9 | ] 10 | 11 | appFileName = "fabricjs_viewport" 12 | 13 | task 'build', 'Build single application file from source files', -> 14 | appContents = new Array remaining = appFiles.length 15 | for file, index in appFiles then do (file, index) -> 16 | fs.readFile "src/#{file}.coffee", 'utf8', (err, fileContents) -> 17 | throw err if err 18 | appContents[index] = fileContents 19 | process() if --remaining is 0 20 | process = -> 21 | fs.writeFile "dist/#{appFileName}.coffee", appContents.join('\n\n'), 'utf8', (err) -> 22 | throw err if err 23 | exec "coffee --compile dist/#{appFileName}.coffee", (err, stdout, stderr) -> 24 | throw err if err 25 | console.log stdout + stderr 26 | fs.unlink "dist/#{appFileName}.coffee", (err) -> 27 | throw err if err 28 | console.log 'Done.' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 SoftwareBrothers.co 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/fabric/canvas_with_viewport.coffee: -------------------------------------------------------------------------------- 1 | class fabric.CanvasWithViewport extends fabric.Canvas 2 | constructor: () -> 3 | @viewport = new fabric.Viewport(@) 4 | @isGrabMode = false 5 | @_isCurrentlyGrabbing = false 6 | super 7 | 8 | setZoom: (zoom) -> 9 | @viewport.setZoom(zoom) 10 | @renderAll() 11 | 12 | 13 | _onMouseMoveInGrabMode: (e) -> 14 | if @_isCurrentlyGrabbing 15 | @viewport.grab(e) 16 | @renderAll() 17 | true 18 | 19 | _onMouseDownInGrabMode: (e) -> 20 | @_isCurrentlyGrabbing = true 21 | @viewport.grabStart(e) 22 | 23 | 24 | _onMouseUpInGrabMode: (e) -> 25 | if @_isCurrentlyGrabbing 26 | @viewport.grabEnd(e) 27 | @_isCurrentlyGrabbing = false 28 | @renderAll() 29 | true 30 | 31 | _draw: (ctx, object) -> 32 | ctx.save() 33 | ctx.scale(@viewport.zoom, @viewport.zoom) 34 | ctx.translate(@viewport.translate().x, @viewport.translate().y) 35 | super 36 | ctx.restore() 37 | 38 | _drawSelection: () -> 39 | ctx = this.contextTop 40 | ctx.save() 41 | ctx.scale(@viewport.zoom,@viewport.zoom) 42 | ctx.translate(@viewport.translate().x, @viewport.translate().y) 43 | super 44 | ctx.restore() 45 | 46 | __onMouseMove: (e) -> 47 | if @isGrabMode 48 | @_onMouseMoveInGrabMode(e) 49 | return 50 | super(@viewport.transform(e)) 51 | 52 | __onMouseDown: (e) -> 53 | if @isGrabMode 54 | @_onMouseDownInGrabMode(e) 55 | return 56 | super(@viewport.transform(e)) 57 | 58 | __onMouseUp: (e) -> 59 | if @isGrabMode 60 | @_onMouseUpInGrabMode(e) 61 | return 62 | super(@viewport.transform(e)) 63 | -------------------------------------------------------------------------------- /src/fabric/viewport.coffee: -------------------------------------------------------------------------------- 1 | class fabric.Viewport 2 | constructor: (canvas) -> 3 | @i = 0 4 | @position = new fabric.Point(0,0) 5 | @zoom = 1 6 | @canvas = canvas 7 | @_resetGrab() 8 | true 9 | 10 | grabStart: (e) -> 11 | @grabStartPointer = @canvas.getPointer(e) 12 | 13 | grab: (e) -> 14 | @grabPointer = @canvas.getPointer(e) 15 | 16 | grabEnd: (e) -> 17 | diff = new fabric.Point(@canvas.getPointer(e).x - @grabStartPointer.x, @canvas.getPointer(e).y - @grabStartPointer.y) 18 | @position = @position.add(diff) 19 | @_resetGrab() 20 | 21 | _resetGrab: () -> 22 | @grabStartPointer = {x: 0, y: 0} 23 | @grabPointer = {x: 0, y: 0} 24 | 25 | setZoom: (newZoom) -> 26 | @_adjustPositionAfterZoom(newZoom) 27 | @zoom = newZoom 28 | 29 | _adjustPositionAfterZoom: (newZoom) -> 30 | halfWidth = @canvas.width / 2 31 | halfHeight = @canvas.height / 2 32 | k = newZoom / @zoom 33 | @position.x = halfWidth - k * (halfWidth - @position.x) 34 | @position.y = halfHeight - k * (halfHeight - @position.y) 35 | 36 | translate: () -> 37 | { 38 | x: (@position.x + @grabPointer.x - @grabStartPointer.x)/@zoom 39 | y: (@position.y + @grabPointer.y - @grabStartPointer.y)/@zoom 40 | } 41 | 42 | transform: (event) -> 43 | touchProp = if event.type == 'touchend' then 'changedTouches' else 'touches' 44 | 45 | if event[touchProp] && event[touchProp][0] 46 | ex = {} 47 | ex[touchProp] = _.map(event[touchProp], (t) => @_transformEventParams(t) ) 48 | $.extend($.Event(event.type), ex) 49 | else 50 | $.extend($.Event(event.type), @_transformEventParams(event)) 51 | 52 | _transformEventParams: (e) -> 53 | offsetTop = @canvas.wrapperEl.getBoundingClientRect().top 54 | offsetLeft = @canvas.wrapperEl.getBoundingClientRect().left 55 | { 56 | which: 1 57 | clientX: (e.clientX-offsetLeft)/@zoom+offsetLeft - @translate().x, 58 | clientY: (e.clientY-offsetTop)/@zoom+offsetTop - @translate().y, 59 | pageX: e.pageX - @translate().x, 60 | pageY: e.pageY - @translate().y, 61 | screenX: e.screenX - @translate().x, 62 | screenY: e.screenY - @translate().y 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fabricjs-viewport 2 | 3 | Simple implementation of viewport and zoom in fabricjs. 4 | 5 | 1. Doesn't change data model, so none of the objects on your canvas is changed after zooming/grabbing 6 | 2. Supports touch devices 7 | 3. Supports free drawing mode 8 | 9 | First [see an example](http://softwarebrothers.github.io/fabricjs-viewport/) 10 | 11 | ### How to use it 12 | 13 | Currently it depends on jquery, however I plan to fix it soon. 14 | In the HEAD of your HTML file include jQuery, fabricjs and fabricjs-viewport. You can find fabricjs-viewport.js in this repo in the /dist/ directory. 15 | 16 | You can invclude those libraries from CDNs (order matters): 17 | 18 | ```javascript 19 | 20 | 21 | 22 | ``` 23 | 24 | Next if you need to use zooming or changing viewport in your project just use fabric.CanvasWithViewport insteed of fabric.Canvas 25 | 26 | var c = new fabric.CanvasWithViewport("id-of-your-canvas"); 27 | 28 | Now you are be able to: 29 | 30 | Turn on grabbing mode: 31 | 32 | ```javascript 33 | c.isGrabMode = true; 34 | ``` 35 | 36 | With this you can change the viewport with drag and drop on the canvas. 37 | 38 | You also can zoom in and out: 39 | 40 | ```javascript 41 | c.setZoom(c.viewport.zoom*1.1); // zoom in by 10% 42 | ``` 43 | 44 | ## OpenSource SoftwareBrothers community 45 | 46 | - [Join the community](https://join.slack.com/t/adminbro/shared_invite/zt-czfb79t1-0U7pn_KCqd5Ts~lbJK0_RA) to get help and be inspired. 47 | - subscribe to our [newsletter](https://www.getrevue.co/profile/adminbro) 48 | 49 | ## License 50 | 51 | fabricjs-viewport is Copyright © 2018 SoftwareBrothers.co. It is free software, and may be redistributed under the terms specified in the [LICENSE](LICENSE.md) file. 52 | 53 | ## About SoftwareBrothers.co 54 | 55 | 56 | 57 | 58 | We are a software company who provides web and mobile development and UX/UI services, friendly team that helps clients from all over the world to transform their businesses and create astonishing products. 59 | 60 | * We are available for [hire](https://softwarebrothers.co/contact). 61 | * If you want to work for us - checkout the [career page](https://softwarebrothers.co/career). 62 | -------------------------------------------------------------------------------- /src/fabric/controls_extension/object.coffee: -------------------------------------------------------------------------------- 1 | _drawControl = fabric.Object.prototype._drawControl 2 | 3 | fabric.Object.prototype._drawControl = (control, ctx, methodName, left, top) -> 4 | zoom = @canvas.viewport?.zoom || 1 5 | ctx.lineWidth = 1 / Math.max(@scaleX, @scaleY) / zoom 6 | _drawControl.apply(@, [control, ctx, methodName, left, top]) 7 | 8 | drawControls = fabric.Object.prototype.drawControls 9 | 10 | fabric.Object.prototype.drawControls = (ctx) -> 11 | zoom = @canvas?.viewport?.zoom || 1 12 | @cornerSize = @cornerSize / zoom 13 | ret = drawControls.apply(@, [ctx]) 14 | @cornerSize = @cornerSize * zoom 15 | ret 16 | 17 | _setCornerCoords = fabric.Object.prototype._setCornerCoords 18 | 19 | fabric.Object.prototype._setCornerCoords = () -> 20 | zoom = @canvas?.viewport?.zoom || 1 21 | @cornerSize = @cornerSize / zoom 22 | ret = _setCornerCoords.apply(@) 23 | @cornerSize = @cornerSize * zoom 24 | ret 25 | 26 | 27 | fabric.Object.prototype.drawBorders = (ctx) -> 28 | return @ unless this.hasBorders 29 | zoom = @canvas?.viewport?.zoom || 1 30 | 31 | padding = this.padding 32 | padding2 = padding * 2 33 | strokeWidth = ~~(this.strokeWidth / 2) * 2 34 | 35 | ctx.save() 36 | 37 | ctx.globalAlpha = if this.isMoving then this.borderOpacityWhenMoving else 1 38 | ctx.strokeStyle = this.borderColor 39 | 40 | scaleX = 1 / this._constrainScale(this.scaleX) 41 | scaleY = 1 / this._constrainScale(this.scaleY) 42 | 43 | ctx.lineWidth = 1 / this.borderScaleFactor / zoom; 44 | 45 | ctx.scale(scaleX, scaleY) 46 | 47 | w = this.getWidth() 48 | h = this.getHeight() 49 | 50 | ctx.strokeRect( 51 | (-(w / 2) - padding - strokeWidth / 2 * this.scaleX) - 0.5 / zoom, 52 | (-(h / 2) - padding - strokeWidth / 2 * this.scaleY) - 0.5 / zoom, 53 | (w + padding2 + strokeWidth * this.scaleX) + 1 / zoom, 54 | (h + padding2 + strokeWidth * this.scaleY) + 1 / zoom 55 | ) 56 | 57 | if this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls 58 | rotateHeight = ( 59 | if this.flipY then h + ((strokeWidth * this.scaleY) + (padding * 2))*zoom else -h - ((strokeWidth * this.scaleY) + (padding * 2))*zoom 60 | ) / 2 61 | 62 | ctx.beginPath() 63 | ctx.moveTo(0, rotateHeight) 64 | ctx.lineTo(0, rotateHeight + (if this.flipY then this.rotatingPointOffset else -this.rotatingPointOffset)) 65 | ctx.closePath() 66 | ctx.stroke() 67 | 68 | ctx.restore() 69 | return @ 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Canvas with viewport example 4 | 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 |
21 | Edit mode 22 | Draw mode 23 | Grab mode 24 | Zoom in 25 | Zoom out 26 | Clear 27 |
28 | 29 | 92 | 93 | -------------------------------------------------------------------------------- /dist/fabricjs_viewport.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.7.1 2 | (function() { 3 | var drawControls, old, _drawControl, _setCornerCoords, 4 | __hasProp = {}.hasOwnProperty, 5 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 6 | 7 | _drawControl = fabric.Object.prototype._drawControl; 8 | 9 | fabric.Object.prototype._drawControl = function(control, ctx, methodName, left, top) { 10 | var zoom, _ref; 11 | zoom = ((_ref = this.canvas.viewport) != null ? _ref.zoom : void 0) || 1; 12 | ctx.lineWidth = 1 / Math.max(this.scaleX, this.scaleY) / zoom; 13 | return _drawControl.apply(this, [control, ctx, methodName, left, top]); 14 | }; 15 | 16 | drawControls = fabric.Object.prototype.drawControls; 17 | 18 | fabric.Object.prototype.drawControls = function(ctx) { 19 | var ret, zoom, _ref, _ref1; 20 | zoom = ((_ref = this.canvas) != null ? (_ref1 = _ref.viewport) != null ? _ref1.zoom : void 0 : void 0) || 1; 21 | this.cornerSize = this.cornerSize / zoom; 22 | ret = drawControls.apply(this, [ctx]); 23 | this.cornerSize = this.cornerSize * zoom; 24 | return ret; 25 | }; 26 | 27 | _setCornerCoords = fabric.Object.prototype._setCornerCoords; 28 | 29 | fabric.Object.prototype._setCornerCoords = function() { 30 | var ret, zoom, _ref, _ref1; 31 | zoom = ((_ref = this.canvas) != null ? (_ref1 = _ref.viewport) != null ? _ref1.zoom : void 0 : void 0) || 1; 32 | this.cornerSize = this.cornerSize / zoom; 33 | ret = _setCornerCoords.apply(this); 34 | this.cornerSize = this.cornerSize * zoom; 35 | return ret; 36 | }; 37 | 38 | fabric.Object.prototype.drawBorders = function(ctx) { 39 | var h, padding, padding2, rotateHeight, scaleX, scaleY, strokeWidth, w, zoom, _ref, _ref1; 40 | if (!this.hasBorders) { 41 | return this; 42 | } 43 | zoom = ((_ref = this.canvas) != null ? (_ref1 = _ref.viewport) != null ? _ref1.zoom : void 0 : void 0) || 1; 44 | padding = this.padding; 45 | padding2 = padding * 2; 46 | strokeWidth = ~~(this.strokeWidth / 2) * 2; 47 | ctx.save(); 48 | ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1; 49 | ctx.strokeStyle = this.borderColor; 50 | scaleX = 1 / this._constrainScale(this.scaleX); 51 | scaleY = 1 / this._constrainScale(this.scaleY); 52 | ctx.lineWidth = 1 / this.borderScaleFactor / zoom; 53 | ctx.scale(scaleX, scaleY); 54 | w = this.getWidth(); 55 | h = this.getHeight(); 56 | ctx.strokeRect((-(w / 2) - padding - strokeWidth / 2 * this.scaleX) - 0.5 / zoom, (-(h / 2) - padding - strokeWidth / 2 * this.scaleY) - 0.5 / zoom, (w + padding2 + strokeWidth * this.scaleX) + 1 / zoom, (h + padding2 + strokeWidth * this.scaleY) + 1 / zoom); 57 | if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) { 58 | rotateHeight = (this.flipY ? h + ((strokeWidth * this.scaleY) + (padding * 2)) * zoom : -h - ((strokeWidth * this.scaleY) + (padding * 2)) * zoom) / 2; 59 | ctx.beginPath(); 60 | ctx.moveTo(0, rotateHeight); 61 | ctx.lineTo(0, rotateHeight + (this.flipY ? this.rotatingPointOffset : -this.rotatingPointOffset)); 62 | ctx.closePath(); 63 | ctx.stroke(); 64 | } 65 | ctx.restore(); 66 | return this; 67 | }; 68 | 69 | fabric.Viewport = (function() { 70 | function Viewport(canvas) { 71 | this.i = 0; 72 | this.position = new fabric.Point(0, 0); 73 | this.zoom = 1; 74 | this.canvas = canvas; 75 | this._resetGrab(); 76 | true; 77 | } 78 | 79 | Viewport.prototype.grabStart = function(e) { 80 | return this.grabStartPointer = this.canvas.getPointer(e); 81 | }; 82 | 83 | Viewport.prototype.grab = function(e) { 84 | return this.grabPointer = this.canvas.getPointer(e); 85 | }; 86 | 87 | Viewport.prototype.grabEnd = function(e) { 88 | var diff; 89 | diff = new fabric.Point(this.canvas.getPointer(e).x - this.grabStartPointer.x, this.canvas.getPointer(e).y - this.grabStartPointer.y); 90 | this.position = this.position.add(diff); 91 | return this._resetGrab(); 92 | }; 93 | 94 | Viewport.prototype._resetGrab = function() { 95 | this.grabStartPointer = { 96 | x: 0, 97 | y: 0 98 | }; 99 | return this.grabPointer = { 100 | x: 0, 101 | y: 0 102 | }; 103 | }; 104 | 105 | Viewport.prototype.setZoom = function(newZoom) { 106 | this._adjustPositionAfterZoom(newZoom); 107 | return this.zoom = newZoom; 108 | }; 109 | 110 | Viewport.prototype._adjustPositionAfterZoom = function(newZoom) { 111 | var halfHeight, halfWidth, k; 112 | halfWidth = this.canvas.width / 2; 113 | halfHeight = this.canvas.height / 2; 114 | k = newZoom / this.zoom; 115 | this.position.x = halfWidth - k * (halfWidth - this.position.x); 116 | return this.position.y = halfHeight - k * (halfHeight - this.position.y); 117 | }; 118 | 119 | Viewport.prototype.translate = function() { 120 | return { 121 | x: (this.position.x + this.grabPointer.x - this.grabStartPointer.x) / this.zoom, 122 | y: (this.position.y + this.grabPointer.y - this.grabStartPointer.y) / this.zoom 123 | }; 124 | }; 125 | 126 | Viewport.prototype.transform = function(event) { 127 | var ex, touchProp; 128 | touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches'; 129 | if (event[touchProp] && event[touchProp][0]) { 130 | ex = {}; 131 | ex[touchProp] = _.map(event[touchProp], (function(_this) { 132 | return function(t) { 133 | return _this._transformEventParams(t); 134 | }; 135 | })(this)); 136 | return $.extend($.Event(event.type), ex); 137 | } else { 138 | return $.extend($.Event(event.type), this._transformEventParams(event)); 139 | } 140 | }; 141 | 142 | Viewport.prototype._transformEventParams = function(e) { 143 | var offsetLeft, offsetTop; 144 | offsetTop = this.canvas.wrapperEl.getBoundingClientRect().top; 145 | offsetLeft = this.canvas.wrapperEl.getBoundingClientRect().left; 146 | return { 147 | which: 1, 148 | clientX: (e.clientX - offsetLeft) / this.zoom + offsetLeft - this.translate().x, 149 | clientY: (e.clientY - offsetTop) / this.zoom + offsetTop - this.translate().y, 150 | pageX: e.pageX - this.translate().x, 151 | pageY: e.pageY - this.translate().y, 152 | screenX: e.screenX - this.translate().x, 153 | screenY: e.screenY - this.translate().y 154 | }; 155 | }; 156 | 157 | return Viewport; 158 | 159 | })(); 160 | 161 | old = fabric.PencilBrush.prototype._render; 162 | 163 | fabric.PencilBrush.prototype._render = function() { 164 | var ctx; 165 | if (this.canvas.viewport) { 166 | ctx = this.canvas.contextTop; 167 | ctx.save(); 168 | ctx.scale(this.canvas.viewport.zoom, this.canvas.viewport.zoom); 169 | ctx.translate(this.canvas.viewport.translate().x, this.canvas.viewport.translate().y); 170 | old.apply(this); 171 | return ctx.restore(); 172 | } else { 173 | return old.apply(this); 174 | } 175 | }; 176 | 177 | fabric.CanvasWithViewport = (function(_super) { 178 | __extends(CanvasWithViewport, _super); 179 | 180 | function CanvasWithViewport() { 181 | this.viewport = new fabric.Viewport(this); 182 | this.isGrabMode = false; 183 | this._isCurrentlyGrabbing = false; 184 | CanvasWithViewport.__super__.constructor.apply(this, arguments); 185 | } 186 | 187 | CanvasWithViewport.prototype.setZoom = function(zoom) { 188 | this.viewport.setZoom(zoom); 189 | return this.renderAll(); 190 | }; 191 | 192 | CanvasWithViewport.prototype._onMouseMoveInGrabMode = function(e) { 193 | if (this._isCurrentlyGrabbing) { 194 | this.viewport.grab(e); 195 | this.renderAll(); 196 | return true; 197 | } 198 | }; 199 | 200 | CanvasWithViewport.prototype._onMouseDownInGrabMode = function(e) { 201 | this._isCurrentlyGrabbing = true; 202 | return this.viewport.grabStart(e); 203 | }; 204 | 205 | CanvasWithViewport.prototype._onMouseUpInGrabMode = function(e) { 206 | if (this._isCurrentlyGrabbing) { 207 | this.viewport.grabEnd(e); 208 | this._isCurrentlyGrabbing = false; 209 | this.renderAll(); 210 | } 211 | return true; 212 | }; 213 | 214 | CanvasWithViewport.prototype._draw = function(ctx, object) { 215 | ctx.save(); 216 | ctx.scale(this.viewport.zoom, this.viewport.zoom); 217 | ctx.translate(this.viewport.translate().x, this.viewport.translate().y); 218 | CanvasWithViewport.__super__._draw.apply(this, arguments); 219 | return ctx.restore(); 220 | }; 221 | 222 | CanvasWithViewport.prototype._drawSelection = function() { 223 | var ctx; 224 | ctx = this.contextTop; 225 | ctx.save(); 226 | ctx.scale(this.viewport.zoom, this.viewport.zoom); 227 | ctx.translate(this.viewport.translate().x, this.viewport.translate().y); 228 | CanvasWithViewport.__super__._drawSelection.apply(this, arguments); 229 | return ctx.restore(); 230 | }; 231 | 232 | CanvasWithViewport.prototype.__onMouseMove = function(e) { 233 | if (this.isGrabMode) { 234 | this._onMouseMoveInGrabMode(e); 235 | return; 236 | } 237 | return CanvasWithViewport.__super__.__onMouseMove.call(this, this.viewport.transform(e)); 238 | }; 239 | 240 | CanvasWithViewport.prototype.__onMouseDown = function(e) { 241 | if (this.isGrabMode) { 242 | this._onMouseDownInGrabMode(e); 243 | return; 244 | } 245 | return CanvasWithViewport.__super__.__onMouseDown.call(this, this.viewport.transform(e)); 246 | }; 247 | 248 | CanvasWithViewport.prototype.__onMouseUp = function(e) { 249 | if (this.isGrabMode) { 250 | this._onMouseUpInGrabMode(e); 251 | return; 252 | } 253 | return CanvasWithViewport.__super__.__onMouseUp.call(this, this.viewport.transform(e)); 254 | }; 255 | 256 | return CanvasWithViewport; 257 | 258 | })(fabric.Canvas); 259 | 260 | }).call(this); 261 | --------------------------------------------------------------------------------