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 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