Last active
December 22, 2017 16:01
-
-
Save vitalyrotari/288b094e38e8e6af8a7c to your computer and use it in GitHub Desktop.
jQuery Eraser Plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Forked from: https://github.com/boblemarin/jQuery.eraser | |
| */ | |
| (function( $ ){ | |
| var $win = $(window); | |
| var Eraser = function(element, options) { | |
| this.$element = $(element); | |
| this.options = options; | |
| this.init_(); | |
| }; | |
| Eraser.prototype.init_ = function() { | |
| if (this.initialized_) { | |
| return; | |
| } | |
| var pos = this.$element.offset(); | |
| this.paths_ = []; | |
| this.data = { | |
| w: this.$element.width(), | |
| h: this.$element.height(), | |
| posX: pos.left, | |
| posY: pos.top, | |
| canvas: document.createElement('canvas'), | |
| size: (this.options && this.options.size) ? this.options.size : 40, | |
| complete: false, | |
| completeRatio: (this.options && this.options.completeRatio) ? this.options.completeRatio : .7, | |
| completeFunction: (this.options && this.options.completeFunction) ? this.options.completeFunction : null, | |
| parts: [], | |
| colParts: 0, | |
| numParts: 0, | |
| ratio: 0, | |
| source: this.$element[0], | |
| touchDown: false, | |
| touchID: -999, | |
| touchX: 0, | |
| touchY: 0, | |
| ptouchX: 0, | |
| ptouchY: 0 | |
| }; | |
| this.data.ctx = this.data.canvas.getContext("2d"); | |
| this.$element.after(this.data.canvas); | |
| var id = this.$element.attr('id') | |
| , className = this.$element.attr('class'); | |
| if (id) { | |
| this.data.canvas.id = this.$element.attr('id'); | |
| } | |
| if (className) { | |
| this.data.canvas.className = this.$element.attr('class'); | |
| } | |
| this.drawCanvas(); | |
| this.$element.remove(); | |
| $(this.data.canvas) | |
| .on('mousedown.eraser', $.proxy(this.mouseDown, this)) | |
| .on('touchstart.eraser', $.proxy(this.touchStart, this)) | |
| .on('touchmove.eraser', $.proxy(this.touchMove, this)) | |
| .on('touchend.eraser', $.proxy(this.touchEnd, this)); | |
| this.collectParts(); | |
| var resize = $.proxy(function() { | |
| var $canvas = $(this.data.canvas) | |
| , $parent = $canvas.parent() | |
| , pos = $canvas.offset(); | |
| this.data.posX = pos.left; | |
| this.data.posY = pos.top; | |
| this.data.w = $parent.width(); | |
| this.data.h = $parent.height(); | |
| this.drawCanvas(); | |
| this.collectParts(); | |
| }, this); | |
| $win.on('resize.eraser.redraw', resize); | |
| $.data(this.data.canvas, 'Eraser', this); | |
| this.initialized_ = true; | |
| }; | |
| Eraser.prototype.collectParts = function() { | |
| this.data.colParts = Math.floor(this.data.w / this.data.size); | |
| this.data.numParts = this.data.colParts * Math.floor(this.data.h / this.data.size); | |
| this.data.parts.length = 0; | |
| var n = this.data.numParts; | |
| while(n--) { | |
| this.data.parts.push(1); | |
| } | |
| }; | |
| Eraser.prototype.drawCanvas = function() { | |
| this.data.canvas.width = this.data.w; | |
| this.data.canvas.height = this.data.h; | |
| this.data.ctx.drawImage(this.data.source, 0, 0 , this.data.w, this.data.h); | |
| this.data.ctx.globalCompositeOperation = "destination-out"; | |
| this.data.ctx.strokeStyle = 'rgba(255,0,0,255)'; | |
| this.data.ctx.lineWidth = this.data.size; | |
| this.data.ctx.lineCap = "round"; | |
| if (this.paths_.length) { | |
| var touchX = this.data.touchX | |
| , touchY = this.data.touchY; | |
| for (var i=0, item; i<this.paths_.length; i++) { | |
| item = this.paths_[i]; | |
| this.data.touchX = item.x1; | |
| this.data.touchY = item.y1; | |
| this.drawLine(item.x2, item.y2, true); | |
| } | |
| this.data.touchX = touchX; | |
| this.data.touchY = touchY; | |
| } | |
| }; | |
| Eraser.prototype.drawLine = function(tx, ty, skipPaths) { | |
| var x1 = this.data.touchX-1 | |
| , y1 = this.data.touchY; | |
| this.data.ctx.beginPath(); | |
| this.data.ctx.moveTo(x1, y1); | |
| this.data.touchX = tx; | |
| this.data.touchY = ty; | |
| this.data.ctx.lineTo(this.data.touchX, this.data.touchY); | |
| this.data.ctx.stroke(); | |
| if (!this.data.complete && !skipPaths) { | |
| this.paths_.push({ | |
| x1: x1, | |
| y1: y1, | |
| x2: tx, | |
| y2: ty | |
| }); | |
| } | |
| } | |
| Eraser.prototype.touchStart = function(event) { | |
| if (!this.data.touchDown ) { | |
| var t = event.originalEvent.changedTouches[0] | |
| , tx = t.pageX - this.data.posX | |
| , ty = t.pageY - this.data.posY; | |
| this.evaluatePoint(tx, ty); | |
| this.data.touchDown = true; | |
| this.data.touchID = t.identifier; | |
| this.data.touchX = tx; | |
| this.data.touchY = ty; | |
| event.preventDefault(); | |
| } | |
| }; | |
| Eraser.prototype.touchMove = function(event) { | |
| if (this.data.touchDown) { | |
| var ta = event.originalEvent.changedTouches | |
| , n = ta.length; | |
| while(n--) { | |
| if (ta[n].identifier == this.data.touchID) { | |
| var tx = ta[n].pageX - this.data.posX | |
| , ty = ta[n].pageY - this.data.posY; | |
| this.evaluatePoint(tx, ty); | |
| this.drawLine(tx, ty); | |
| event.preventDefault(); | |
| break; | |
| } | |
| } | |
| } | |
| }; | |
| Eraser.prototype.touchEnd = function(event) { | |
| if (this.data.touchDown ) { | |
| var ta = event.originalEvent.changedTouches | |
| , n = ta.length; | |
| while(n--) { | |
| if (ta[n].identifier == this.data.touchID) { | |
| this.data.touchDown = false; | |
| event.preventDefault(); | |
| break; | |
| } | |
| } | |
| } | |
| }; | |
| Eraser.prototype.evaluatePoint = function(tx, ty) { | |
| var p = Math.floor(tx/this.data.size) + Math.floor(ty / this.data.size) * this.data.colParts; | |
| if (p >= 0 && p < this.data.numParts ) { | |
| this.data.ratio += this.data.parts[p]; | |
| this.data.parts[p] = 0; | |
| if (!this.data.complete) { | |
| if (this.data.ratio/this.data.numParts >= this.data.completeRatio) { | |
| this.data.complete = true; | |
| if (this.data.completeFunction != null ) { | |
| this.data.completeFunction(); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| Eraser.prototype.mouseDown = function(event) { | |
| var tx = event.pageX - this.data.posX | |
| , ty = event.pageY - this.data.posY; | |
| this.data.touchDown = true; | |
| this.data.touchX = tx; | |
| this.data.touchY = ty; | |
| this.evaluatePoint(tx, ty); | |
| this.drawLine(tx, ty); | |
| $(this.data.canvas).on('mousemove.eraser', $.proxy(this.mouseMove, this)); | |
| $(document).on('mouseup.eraser', $.proxy(this.mouseUp, this)); | |
| event.preventDefault(); | |
| }; | |
| Eraser.prototype.mouseMove = function(event) { | |
| var tx = event.pageX - this.data.posX | |
| , ty = event.pageY - this.data.posY; | |
| this.evaluatePoint(tx, ty); | |
| this.drawLine(tx, ty); | |
| event.preventDefault(); | |
| }; | |
| Eraser.prototype.mouseUp = function(event) { | |
| this.data.touchDown = false; | |
| $(this.data.canvas).unbind('mousemove.eraser'); | |
| $(document).unbind('mouseup.eraser'); | |
| event.preventDefault(); | |
| }; | |
| Eraser.prototype.clear = function() { | |
| this.data.ctx.clearRect(0, 0, this.data.w, this.data.h); | |
| var n = this.data.numParts; | |
| while(n--) { | |
| this.data.parts[n] = 0; | |
| } | |
| this.data.ratio = this.data.numParts; | |
| this.data.complete = true; | |
| if (this.data.completeFunction != null) { | |
| this.data.completeFunction(); | |
| } | |
| }; | |
| Eraser.prototype.size = function(value) { | |
| if (value) { | |
| this.data.size = value; | |
| this.data.ctx.lineWidth = value; | |
| } | |
| }; | |
| Eraser.prototype.reset = function() { | |
| this.paths_.length = 0; | |
| $win.trigger('resize.eraser.redraw'); | |
| this.data.ratio = 0; | |
| this.data.complete = false; | |
| }; | |
| $.fn.eraser = function(method) { | |
| return this.each(function() { | |
| var instance = $.data(this, 'Eraser'); | |
| if (!instance) { | |
| var options = (typeof method === 'object') ? method : {}; | |
| new Eraser(this, options); | |
| } | |
| if (typeof method === 'string' ) { | |
| if (typeof instance[method] === 'function') { | |
| instance[method].apply(instance, arguments); | |
| } else { | |
| $.error('Method ' + method + ' does not yet exist on jQuery.eraser'); | |
| } | |
| } | |
| }); | |
| }; | |
| })( jQuery ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment