http://www.htmleaf.com/ziliaoku/qianduanjiaocheng/201502151385.html

jQuery 缩放 旋转 裁剪图片 Image Cropper

A simple jQuery image cropping plugin.

https://fengyuanchen.github.io/cropper

涂鸦效果

https://github.com/Leimi/drawingboard.js#drawingboardjs

全局定义,从而实现涂鸦的undo,redo,reset

imageBoard = window.imageBoard;
$(".picLabel").click(function() {
$("#firstStep").hide();
$("#zbeubeu").show();
$("#drawing-board").css("width",$(".cropper-canvas img").width());
$("#drawing-board").css("height",$(".cropper-canvas img").height()); imageBoard = new DrawingBoard.Board('drawing-board', {
background: "http://test.file.tiplus.cn/task/16443/1452588926.598544.jpg?timestamp=1481096992278",
color: "#d00",
size: 3,
controls: false,
//controls: [
//'Navigation',
//],
webStorage:false,
//webStorage: 'session',
enlargeYourContainer: true,
stretchImg: true,
droppable: true,
//controlsPosition:"bottom center"
});
$(".cropper-container").hide();
$(".drawing-board-canvas-wrapper").css("width", $(".cropper-canvas").css("witdh"));
$(".drawing-board-canvas-wrapper").css("height", $(".cropper-canvas").css("height"));
$(".drawing-board-canvas-wrapper").css("left", $(".cropper-canvas").css("left"));
$(".drawing-board-canvas-wrapper").css("top", $(".cropper-canvas").css("top")); $("#secondStep").show(); })
$("#undo").click(function(){
//imageBoard.downloadImg();
imageBoard.goBackInHistory();
})
$("#redo").click(function(){
//imageBoard.downloadImg();
imageBoard.goForthInHistory();
})
$(".destroy").click(function(){
//imageBoard.downloadImg();
imageBoard.reset({ background: true });
})

可以实现图片放大缩小,可以在途中增加文字:

https://github.com/lamida/canvas-draw-undo

http://jsfiddle.net/epistemex/95r85zh4/

http://phrogz.net/tmp/canvas_zoom_to_cursor.html

图片放大缩小拖放

通过cropper完成canvas的旋转、放大或者缩小,修改cropper使得drawingboardjs也同步修改

    var $image = $('#image');
$image.cropper({
aspectRatio: 16 / 9,
movable: true,
dragMode:'move',
crop: function(e) {
// Output the result data for cropping image.
},
built: function () {
croppable = true;
}
});
setTimeout(function(){
clearCanvas();
}, 1000);
$(".rotate").click(function(){
var croppedCanvas;
if (!croppable) {
return;
}
croppedCanvas = $image.cropper('rotate', -90);
$(".cropper-canvas img").css("display","none");
});
$(".enlarge_pic").click(function(){
var croppedCanvas;
if (!croppable) {
return;
}
croppedCanvas = $image.cropper('zoom', 0.1);
$(".cropper-canvas img").css("display","none");
});
$(".shrink_pic").click(function(){
var croppedCanvas;
if (!croppable) {
return;
}
croppedCanvas = $image.cropper('zoom', -0.1);
$(".cropper-canvas img").css("display","none");
});

修改后的cropper文件:

/*!
* Cropper v2.3.4
* https://github.com/fengyuanchen/cropper
*
* Copyright (c) 2014-2016 Fengyuan Chen and contributors
* Released under the MIT license
*
* Date: 2016-09-03T05:50:45.412Z
*/ (function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node / CommonJS
factory(require('jquery'));
} else {
// Browser globals.
factory(jQuery);
}
})(function ($) { 'use strict'; // Globals
var $window = $(window);
var $document = $(document);
var location = window.location;
var navigator = window.navigator;
var ArrayBuffer = window.ArrayBuffer;
var Uint8Array = window.Uint8Array;
var DataView = window.DataView;
var btoa = window.btoa; // Constants
var NAMESPACE = 'cropper'; // Classes
var CLASS_MODAL = 'cropper-modal';
var CLASS_HIDE = 'cropper-hide';
var CLASS_HIDDEN = 'cropper-hidden';
var CLASS_INVISIBLE = 'cropper-invisible';
var CLASS_MOVE = 'cropper-move';
var CLASS_CROP = 'cropper-crop';
var CLASS_DISABLED = 'cropper-disabled';
var CLASS_BG = 'cropper-bg'; // Events
var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown';
var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove';
var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel';
var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
var EVENT_DBLCLICK = 'dblclick';
var EVENT_LOAD = 'load.' + NAMESPACE;
var EVENT_ERROR = 'error.' + NAMESPACE;
var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace
var EVENT_BUILD = 'build.' + NAMESPACE;
var EVENT_BUILT = 'built.' + NAMESPACE;
var EVENT_CROP_START = 'cropstart.' + NAMESPACE;
var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE;
var EVENT_CROP_END = 'cropend.' + NAMESPACE;
var EVENT_CROP = 'crop.' + NAMESPACE;
var EVENT_ZOOM = 'zoom.' + NAMESPACE; // RegExps
var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/;
var REGEXP_DATA_URL = /^data:/;
var REGEXP_DATA_URL_HEAD = /^data:([^;]+);base64,/;
var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg.*;base64,/; // Data keys
var DATA_PREVIEW = 'preview';
var DATA_ACTION = 'action'; // Actions
var ACTION_EAST = 'e';
var ACTION_WEST = 'w';
var ACTION_SOUTH = 's';
var ACTION_NORTH = 'n';
var ACTION_SOUTH_EAST = 'se';
var ACTION_SOUTH_WEST = 'sw';
var ACTION_NORTH_EAST = 'ne';
var ACTION_NORTH_WEST = 'nw';
var ACTION_ALL = 'all';
var ACTION_CROP = 'crop';
var ACTION_MOVE = 'move';
var ACTION_ZOOM = 'zoom';
var ACTION_NONE = 'none'; // Supports
var SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext);
var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); // Maths
var num = Number;
var min = Math.min;
var max = Math.max;
var abs = Math.abs;
var sin = Math.sin;
var cos = Math.cos;
var sqrt = Math.sqrt;
var round = Math.round;
var floor = Math.floor; // Utilities
var fromCharCode = String.fromCharCode; function isNumber(n) {
return typeof n === 'number' && !isNaN(n);
} function isUndefined(n) {
return typeof n === 'undefined';
} function toArray(obj, offset) {
var args = []; // This is necessary for IE8
if (isNumber(offset)) {
args.push(offset);
} return args.slice.apply(obj, args);
} // Custom proxy to avoid jQuery's guid
function proxy(fn, context) {
var args = toArray(arguments, 2); return function () {
return fn.apply(context, args.concat(toArray(arguments)));
};
} function isCrossOriginURL(url) {
var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i); return parts && (
parts[1] !== location.protocol ||
parts[2] !== location.hostname ||
parts[3] !== location.port
);
} function addTimestamp(url) {
var timestamp = 'timestamp=' + (new Date()).getTime(); return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
} function getCrossOrigin(crossOrigin) {
return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : '';
} function getImageSize(image, callback) {
var newImage; // Modern browsers (ignore Safari, #120 & #509)
if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) {
return callback(image.naturalWidth, image.naturalHeight);
} // IE8: Don't use `new Image()` here (#319)
newImage = document.createElement('img'); newImage.onload = function () {
callback(this.width, this.height);
}; newImage.src = image.src;
} function getTransform(options) {
var transforms = [];
var rotate = options.rotate;
var scaleX = options.scaleX;
var scaleY = options.scaleY; // Rotate should come first before scale to match orientation transform
if (isNumber(rotate) && rotate !== 0) {
transforms.push('rotate(' + rotate + 'deg)');
} if (isNumber(scaleX) && scaleX !== 1) {
transforms.push('scaleX(' + scaleX + ')');
} if (isNumber(scaleY) && scaleY !== 1) {
transforms.push('scaleY(' + scaleY + ')');
} return transforms.length ? transforms.join(' ') : 'none';
} function getRotatedSizes(data, isReversed) {
var deg = abs(data.degree) % 180;
var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180;
var sinArc = sin(arc);
var cosArc = cos(arc);
var width = data.width;
var height = data.height;
var aspectRatio = data.aspectRatio;
var newWidth;
var newHeight; if (!isReversed) {
newWidth = width * cosArc + height * sinArc;
newHeight = width * sinArc + height * cosArc;
} else {
newWidth = width / (cosArc + sinArc / aspectRatio);
newHeight = newWidth / aspectRatio;
} return {
width: newWidth,
height: newHeight
};
} function getSourceCanvas(image, data) {
var canvas = $('<canvas>')[0];
var context = canvas.getContext('2d');
var dstX = 0;
var dstY = 0;
var dstWidth = data.naturalWidth;
var dstHeight = data.naturalHeight;
var rotate = data.rotate;
var scaleX = data.scaleX;
var scaleY = data.scaleY;
var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1);
var rotatable = isNumber(rotate) && rotate !== 0;
var advanced = rotatable || scalable;
var canvasWidth = dstWidth * abs(scaleX || 1);
var canvasHeight = dstHeight * abs(scaleY || 1);
var translateX;
var translateY;
var rotated; if (scalable) {
translateX = canvasWidth / 2;
translateY = canvasHeight / 2;
} if (rotatable) {
rotated = getRotatedSizes({
width: canvasWidth,
height: canvasHeight,
degree: rotate
}); canvasWidth = rotated.width;
canvasHeight = rotated.height;
translateX = canvasWidth / 2;
translateY = canvasHeight / 2;
} canvas.width = canvasWidth;
canvas.height = canvasHeight; if (advanced) {
dstX = -dstWidth / 2;
dstY = -dstHeight / 2; context.save();
context.translate(translateX, translateY);
} // Rotate should come first before scale as in the "getTransform" function
if (rotatable) {
context.rotate(rotate * Math.PI / 180);
} if (scalable) {
context.scale(scaleX, scaleY);
} context.drawImage(image, floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight)); if (advanced) {
context.restore();
} return canvas;
} function getTouchesCenter(touches) {
var length = touches.length;
var pageX = 0;
var pageY = 0; if (length) {
$.each(touches, function (i, touch) {
pageX += touch.pageX;
pageY += touch.pageY;
}); pageX /= length;
pageY /= length;
} return {
pageX: pageX,
pageY: pageY
};
} function getStringFromCharCode(dataView, start, length) {
var str = '';
var i; for (i = start, length += start; i < length; i++) {
str += fromCharCode(dataView.getUint8(i));
} return str;
} function getOrientation(arrayBuffer) {
var dataView = new DataView(arrayBuffer);
var length = dataView.byteLength;
var orientation;
var exifIDCode;
var tiffOffset;
var firstIFDOffset;
var littleEndian;
var endianness;
var app1Start;
var ifdStart;
var offset;
var i; // Only handle JPEG image (start by 0xFFD8)
if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
offset = 2; while (offset < length) {
if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
app1Start = offset;
break;
} offset++;
}
} if (app1Start) {
exifIDCode = app1Start + 4;
tiffOffset = app1Start + 10; if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
endianness = dataView.getUint16(tiffOffset);
littleEndian = endianness === 0x4949; if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); if (firstIFDOffset >= 0x00000008) {
ifdStart = tiffOffset + firstIFDOffset;
}
}
}
}
} if (ifdStart) {
length = dataView.getUint16(ifdStart, littleEndian); for (i = 0; i < length; i++) {
offset = ifdStart + i * 12 + 2; if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) { // 8 is the offset of the current tag's value
offset += 8; // Get the original orientation value
orientation = dataView.getUint16(offset, littleEndian); // Override the orientation with its default value for Safari (#120)
if (IS_SAFARI_OR_UIWEBVIEW) {
dataView.setUint16(offset, 1, littleEndian);
} break;
}
}
} return orientation;
} function dataURLToArrayBuffer(dataURL) {
var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');
var binary = atob(base64);
var length = binary.length;
var arrayBuffer = new ArrayBuffer(length);
var dataView = new Uint8Array(arrayBuffer);
var i; for (i = 0; i < length; i++) {
dataView[i] = binary.charCodeAt(i);
} return arrayBuffer;
} // Only available for JPEG image
function arrayBufferToDataURL(arrayBuffer) {
var dataView = new Uint8Array(arrayBuffer);
var length = dataView.length;
var base64 = '';
var i; for (i = 0; i < length; i++) {
base64 += fromCharCode(dataView[i]);
} return 'data:image/jpeg;base64,' + btoa(base64);
} function Cropper(element, options) {
this.$element = $(element);
this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
this.isLoaded = false;
this.isBuilt = false;
this.isCompleted = false;
this.isRotated = false;
this.isCropped = false;
this.isDisabled = false;
this.isReplaced = false;
this.isLimited = false;
this.wheeling = false;
this.isImg = false;
this.originalUrl = '';
this.canvas = null;
this.cropBox = null;
this.init();
} Cropper.prototype = {
constructor: Cropper, init: function () {
var $this = this.$element;
var url; if ($this.is('img')) {
this.isImg = true; // Should use `$.fn.attr` here. e.g.: "img/picture.jpg"
this.originalUrl = url = $this.attr('src'); // Stop when it's a blank image
if (!url) {
return;
} // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg"
url = $this.prop('src');
} else if ($this.is('canvas') && SUPPORT_CANVAS) {
url = $this[0].toDataURL();
} this.load(url);
}, // A shortcut for triggering custom events
trigger: function (type, data) {
var e = $.Event(type, data); this.$element.trigger(e); return e;
}, load: function (url) {
var options = this.options;
var $this = this.$element;
var read;
var xhr; if (!url) {
return;
} // Trigger build event first
$this.one(EVENT_BUILD, options.build); if (this.trigger(EVENT_BUILD).isDefaultPrevented()) {
return;
} this.url = url;
this.image = {}; if (!options.checkOrientation || !ArrayBuffer) {
return this.clone();
} read = $.proxy(this.read, this); // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari
if (REGEXP_DATA_URL.test(url)) {
return REGEXP_DATA_URL_JPEG.test(url) ?
read(dataURLToArrayBuffer(url)) :
this.clone();
} xhr = new XMLHttpRequest(); xhr.onerror = xhr.onabort = $.proxy(function () {
this.clone();
}, this); xhr.onload = function () {
read(this.response);
}; if (options.checkCrossOrigin && isCrossOriginURL(url) && $this.prop('crossOrigin')) {
url = addTimestamp(url);
} xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.send();
}, read: function (arrayBuffer) {
var options = this.options;
var orientation = getOrientation(arrayBuffer);
var image = this.image;
var rotate = 0;
var scaleX = 1;
var scaleY = 1; if (orientation > 1) {
this.url = arrayBufferToDataURL(arrayBuffer); switch (orientation) { // flip horizontal
case 2:
scaleX = -1;
break; // rotate left 180°
case 3:
rotate = -180;
break; // flip vertical
case 4:
scaleY = -1;
break; // flip vertical + rotate right 90°
case 5:
rotate = 90;
scaleY = -1;
break; // rotate right 90°
case 6:
rotate = 90;
break; // flip horizontal + rotate right 90°
case 7:
rotate = 90;
scaleX = -1;
break; // rotate left 90°
case 8:
rotate = -90;
break;
}
} if (options.rotatable) {
image.rotate = rotate;
} if (options.scalable) {
image.scaleX = scaleX;
image.scaleY = scaleY;
} this.clone();
}, clone: function () {
var options = this.options;
var $this = this.$element;
var url = this.url;
var crossOrigin = '';
var crossOriginUrl;
var $clone; if (options.checkCrossOrigin && isCrossOriginURL(url)) {
crossOrigin = $this.prop('crossOrigin'); if (crossOrigin) {
crossOriginUrl = url;
} else {
crossOrigin = 'anonymous'; // Bust cache (#148) when there is not a "crossOrigin" property
crossOriginUrl = addTimestamp(url);
}
} this.crossOrigin = crossOrigin;
this.crossOriginUrl = crossOriginUrl;
this.$clone = $clone = $('<img' + getCrossOrigin(crossOrigin) + ' src="' + (crossOriginUrl || url) + '">'); if (this.isImg) {
if ($this[0].complete) {
this.start();
} else {
$this.one(EVENT_LOAD, $.proxy(this.start, this));
}
} else {
$clone.
one(EVENT_LOAD, $.proxy(this.start, this)).
one(EVENT_ERROR, $.proxy(this.stop, this)).
addClass(CLASS_HIDE).
insertAfter($this);
}
}, start: function () {
var $image = this.$element;
var $clone = this.$clone; if (!this.isImg) {
$clone.off(EVENT_ERROR, this.stop);
$image = $clone;
} getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) {
$.extend(this.image, {
naturalWidth: naturalWidth,
naturalHeight: naturalHeight,
aspectRatio: naturalWidth / naturalHeight
}); this.isLoaded = true;
this.build();
}, this));
}, stop: function () {
this.$clone.remove();
this.$clone = null;
}, build: function () {
var options = this.options;
var $this = this.$element;
var $clone = this.$clone;
var $cropper;
var $cropBox;
var $face; if (!this.isLoaded) {
return;
} // Unbuild first when replace
if (this.isBuilt) {
this.unbuild();
} // Create cropper elements
this.$container = $this.parent();
this.$cropper = $cropper = $(Cropper.TEMPLATE);
this.$canvas = $cropper.find('.cropper-canvas').append($clone);
this.$dragBox = $cropper.find('.cropper-drag-box');
this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
this.$viewBox = $cropper.find('.cropper-view-box');
this.$face = $face = $cropBox.find('.cropper-face'); // Hide the original image
$this.addClass(CLASS_HIDDEN).after($cropper); // Show the clone image if is hidden
if (!this.isImg) {
$clone.removeClass(CLASS_HIDE);
} this.initPreview();
this.bind(); options.aspectRatio = max(0, options.aspectRatio) || NaN;
options.viewMode = max(0, min(3, round(options.viewMode))) || 0; if (options.autoCrop) {
this.isCropped = true; if (options.modal) {
this.$dragBox.addClass(CLASS_MODAL);
}
} else {
$cropBox.addClass(CLASS_HIDDEN);
} if (!options.guides) {
$cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
} if (!options.center) {
$cropBox.find('.cropper-center').addClass(CLASS_HIDDEN);
} if (options.cropBoxMovable) {
$face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL);
} if (!options.highlight) {
$face.addClass(CLASS_INVISIBLE);
} if (options.background) {
$cropper.addClass(CLASS_BG);
} if (!options.cropBoxResizable) {
$cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
} this.setDragMode(options.dragMode);
this.render();
this.isBuilt = true;
this.setData(options.data);
$this.one(EVENT_BUILT, options.built); // Trigger the built event asynchronously to keep `data('cropper')` is defined
this.completing = setTimeout($.proxy(function () {
this.trigger(EVENT_BUILT);
this.trigger(EVENT_CROP, this.getData());
this.isCompleted = true;
}, this), 0);
}, unbuild: function () {
if (!this.isBuilt) {
return;
} if (!this.isCompleted) {
clearTimeout(this.completing);
} this.isBuilt = false;
this.isCompleted = false;
this.initialImage = null; // Clear `initialCanvas` is necessary when replace
this.initialCanvas = null;
this.initialCropBox = null;
this.container = null;
this.canvas = null; // Clear `cropBox` is necessary when replace
this.cropBox = null;
this.unbind(); this.resetPreview();
this.$preview = null; this.$viewBox = null;
this.$cropBox = null;
this.$dragBox = null;
this.$canvas = null;
this.$container = null; this.$cropper.remove();
this.$cropper = null;
}, render: function () {
this.initContainer();
this.initCanvas();
this.initCropBox(); this.renderCanvas(); if (this.isCropped) {
this.renderCropBox();
}
}, initContainer: function () {
var options = this.options;
var $this = this.$element;
var $container = this.$container;
var $cropper = this.$cropper; $cropper.addClass(CLASS_HIDDEN);
$this.removeClass(CLASS_HIDDEN); $cropper.css((this.container = {
width: max($container.width(), num(options.minContainerWidth) || 200),
height: max($container.height(), num(options.minContainerHeight) || 100)
})); $this.addClass(CLASS_HIDDEN);
$cropper.removeClass(CLASS_HIDDEN);
}, // Canvas (image wrapper)
initCanvas: function () {
var viewMode = this.options.viewMode;
var container = this.container;
var containerWidth = container.width;
var containerHeight = container.height;
var image = this.image;
var imageNaturalWidth = image.naturalWidth;
var imageNaturalHeight = image.naturalHeight;
var is90Degree = abs(image.rotate) === 90;
var naturalWidth = is90Degree ? imageNaturalHeight : imageNaturalWidth;
var naturalHeight = is90Degree ? imageNaturalWidth : imageNaturalHeight;
var aspectRatio = naturalWidth / naturalHeight;
var canvasWidth = containerWidth;
var canvasHeight = containerHeight;
var canvas; if (containerHeight * aspectRatio > containerWidth) {
if (viewMode === 3) {
canvasWidth = containerHeight * aspectRatio;
} else {
canvasHeight = containerWidth / aspectRatio;
}
} else {
if (viewMode === 3) {
canvasHeight = containerWidth / aspectRatio;
} else {
canvasWidth = containerHeight * aspectRatio;
}
}
canvasWidth = canvasWidth * 0.8;
canvasHeight = canvasHeight * 0.8; canvas = {
naturalWidth: naturalWidth,
naturalHeight: naturalHeight,
aspectRatio: aspectRatio,
width: canvasWidth,
height: canvasHeight
}; canvas.oldLeft = canvas.left = (containerWidth - canvasWidth) / 2;
canvas.oldTop = canvas.top = (containerHeight - canvasHeight) / 2; this.canvas = canvas;
this.isLimited = (viewMode === 1 || viewMode === 2);
this.limitCanvas(true, true);
this.initialImage = $.extend({}, image);
this.initialCanvas = $.extend({}, canvas);
}, limitCanvas: function (isSizeLimited, isPositionLimited) {
var options = this.options;
var viewMode = options.viewMode;
var container = this.container;
var containerWidth = container.width;
var containerHeight = container.height;
var canvas = this.canvas;
var aspectRatio = canvas.aspectRatio;
var cropBox = this.cropBox;
var isCropped = this.isCropped && cropBox;
var minCanvasWidth;
var minCanvasHeight;
var newCanvasLeft;
var newCanvasTop; if (isSizeLimited) {
minCanvasWidth = num(options.minCanvasWidth) || 0;
minCanvasHeight = num(options.minCanvasHeight) || 0; if (viewMode) {
if (viewMode > 1) {
minCanvasWidth = max(minCanvasWidth, containerWidth);
minCanvasHeight = max(minCanvasHeight, containerHeight); if (viewMode === 3) {
if (minCanvasHeight * aspectRatio > minCanvasWidth) {
minCanvasWidth = minCanvasHeight * aspectRatio;
} else {
minCanvasHeight = minCanvasWidth / aspectRatio;
}
}
} else {
if (minCanvasWidth) {
minCanvasWidth = max(minCanvasWidth, isCropped ? cropBox.width : 0);
} else if (minCanvasHeight) {
minCanvasHeight = max(minCanvasHeight, isCropped ? cropBox.height : 0);
} else if (isCropped) {
minCanvasWidth = cropBox.width;
minCanvasHeight = cropBox.height; if (minCanvasHeight * aspectRatio > minCanvasWidth) {
minCanvasWidth = minCanvasHeight * aspectRatio;
} else {
minCanvasHeight = minCanvasWidth / aspectRatio;
}
}
}
} if (minCanvasWidth && minCanvasHeight) {
if (minCanvasHeight * aspectRatio > minCanvasWidth) {
minCanvasHeight = minCanvasWidth / aspectRatio;
} else {
minCanvasWidth = minCanvasHeight * aspectRatio;
}
} else if (minCanvasWidth) {
minCanvasHeight = minCanvasWidth / aspectRatio;
} else if (minCanvasHeight) {
minCanvasWidth = minCanvasHeight * aspectRatio;
} canvas.minWidth = minCanvasWidth;
canvas.minHeight = minCanvasHeight;
canvas.maxWidth = Infinity;
canvas.maxHeight = Infinity;
} if (isPositionLimited) {
if (viewMode) {
newCanvasLeft = containerWidth - canvas.width;
newCanvasTop = containerHeight - canvas.height; canvas.minLeft = min(0, newCanvasLeft);
canvas.minTop = min(0, newCanvasTop);
canvas.maxLeft = max(0, newCanvasLeft);
canvas.maxTop = max(0, newCanvasTop); if (isCropped && this.isLimited) {
canvas.minLeft = min(
cropBox.left,
cropBox.left + cropBox.width - canvas.width
);
canvas.minTop = min(
cropBox.top,
cropBox.top + cropBox.height - canvas.height
);
canvas.maxLeft = cropBox.left;
canvas.maxTop = cropBox.top; if (viewMode === 2) {
if (canvas.width >= containerWidth) {
canvas.minLeft = min(0, newCanvasLeft);
canvas.maxLeft = max(0, newCanvasLeft);
} if (canvas.height >= containerHeight) {
canvas.minTop = min(0, newCanvasTop);
canvas.maxTop = max(0, newCanvasTop);
}
}
}
} else {
canvas.minLeft = -canvas.width;
canvas.minTop = -canvas.height;
canvas.maxLeft = containerWidth;
canvas.maxTop = containerHeight;
}
}
}, renderCanvas: function (isChanged) {
var canvas = this.canvas;
var image = this.image;
var rotate = image.rotate;
var naturalWidth = image.naturalWidth;
var naturalHeight = image.naturalHeight;
var aspectRatio;
var rotated; if (this.isRotated) {
this.isRotated = false; // Computes rotated sizes with image sizes
rotated = getRotatedSizes({
width: image.width,
height: image.height,
degree: rotate
}); aspectRatio = rotated.width / rotated.height; if (aspectRatio !== canvas.aspectRatio) {
canvas.left -= (rotated.width - canvas.width) / 2;
canvas.top -= (rotated.height - canvas.height) / 2;
canvas.width = rotated.width;
canvas.height = rotated.height;
canvas.aspectRatio = aspectRatio;
canvas.naturalWidth = naturalWidth;
canvas.naturalHeight = naturalHeight; // Computes rotated sizes with natural image sizes
if (rotate % 180) {
rotated = getRotatedSizes({
width: naturalWidth,
height: naturalHeight,
degree: rotate
}); canvas.naturalWidth = rotated.width;
canvas.naturalHeight = rotated.height;
} this.limitCanvas(true, false);
}
} if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) {
canvas.left = canvas.oldLeft;
} if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) {
canvas.top = canvas.oldTop;
} canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth);
canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight); this.limitCanvas(false, true); canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft);
canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop); this.$canvas.css({
width: canvas.width,
height: canvas.height,
left: canvas.left,
top: canvas.top
});
//add by zhaoliang 20161224
$("#drawing-board").css({
width: canvas.width,
height: canvas.height,
left: canvas.left,
top: canvas.top
});
$(".drawing-board-canvas").css({
width: canvas.width,
height: canvas.height
});
//add end this.renderImage(); if (this.isCropped && this.isLimited) {
this.limitCropBox(true, true);
} if (isChanged) {
this.output();
}
}, renderImage: function (isChanged) {
var canvas = this.canvas;
var image = this.image;
var reversed; if (image.rotate) {
reversed = getRotatedSizes({
width: canvas.width,
height: canvas.height,
degree: image.rotate,
aspectRatio: image.aspectRatio
}, true);
} $.extend(image, reversed ? {
width: reversed.width,
height: reversed.height,
left: (canvas.width - reversed.width) / 2,
top: (canvas.height - reversed.height) / 2
} : {
width: canvas.width,
height: canvas.height,
left: 0,
top: 0
}); this.$clone.css({
width: image.width,
height: image.height,
marginLeft: image.left,
marginTop: image.top,
transform: getTransform(image)
}); //图片旋转的时候,canvas也旋转
$(".drawing-board-canvas").css({
width: image.width,
height: image.height,
marginLeft: image.left,
marginTop: image.top,
transform: getTransform(image)
});
//end if (isChanged) {
this.output();
}
}, initCropBox: function () {
var options = this.options;
var canvas = this.canvas;
var aspectRatio = options.aspectRatio;
var autoCropArea = num(options.autoCropArea) || 0.8;
var cropBox = {
width: canvas.width,
height: canvas.height
}; if (aspectRatio) {
if (canvas.height * aspectRatio > canvas.width) {
cropBox.height = cropBox.width / aspectRatio;
} else {
cropBox.width = cropBox.height * aspectRatio;
}
} //add by zhaoliang 20161224
canvas.top = 10;
$("#drawing-board").css({
width: canvas.width,
height: canvas.height,
left: canvas.left,
top: canvas.top
});
$(".drawing-board-canvas").css({
width: canvas.width,
height: canvas.height
});
//$(".drawing-board-canvas").attr({
// width: canvas.width,
// height: canvas.height
//});
//add end
this.cropBox = cropBox;
this.limitCropBox(true, true); // Initialize auto crop area
cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); // The width of auto crop area must large than "minWidth", and the height too. (#164)
cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea);
cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea);
cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2;
cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2; this.initialCropBox = $.extend({}, cropBox);
}, limitCropBox: function (isSizeLimited, isPositionLimited) {
var options = this.options;
var aspectRatio = options.aspectRatio;
var container = this.container;
var containerWidth = container.width;
var containerHeight = container.height;
var canvas = this.canvas;
var cropBox = this.cropBox;
var isLimited = this.isLimited;
var minCropBoxWidth;
var minCropBoxHeight;
var maxCropBoxWidth;
var maxCropBoxHeight; if (isSizeLimited) {
minCropBoxWidth = num(options.minCropBoxWidth) || 0;
minCropBoxHeight = num(options.minCropBoxHeight) || 0; // The min/maxCropBoxWidth/Height must be less than containerWidth/Height
minCropBoxWidth = min(minCropBoxWidth, containerWidth);
minCropBoxHeight = min(minCropBoxHeight, containerHeight);
maxCropBoxWidth = min(containerWidth, isLimited ? canvas.width : containerWidth);
maxCropBoxHeight = min(containerHeight, isLimited ? canvas.height : containerHeight); if (aspectRatio) {
if (minCropBoxWidth && minCropBoxHeight) {
if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {
minCropBoxHeight = minCropBoxWidth / aspectRatio;
} else {
minCropBoxWidth = minCropBoxHeight * aspectRatio;
}
} else if (minCropBoxWidth) {
minCropBoxHeight = minCropBoxWidth / aspectRatio;
} else if (minCropBoxHeight) {
minCropBoxWidth = minCropBoxHeight * aspectRatio;
} if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {
maxCropBoxHeight = maxCropBoxWidth / aspectRatio;
} else {
maxCropBoxWidth = maxCropBoxHeight * aspectRatio;
}
} // The minWidth/Height must be less than maxWidth/Height
cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth);
cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight);
cropBox.maxWidth = maxCropBoxWidth;
cropBox.maxHeight = maxCropBoxHeight;
} if (isPositionLimited) {
if (isLimited) {
cropBox.minLeft = max(0, canvas.left);
cropBox.minTop = max(0, canvas.top);
cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height;
} else {
cropBox.minLeft = 0;
cropBox.minTop = 0;
cropBox.maxLeft = containerWidth - cropBox.width;
cropBox.maxTop = containerHeight - cropBox.height;
}
}
}, renderCropBox: function () {
var options = this.options;
var container = this.container;
var containerWidth = container.width;
var containerHeight = container.height;
var cropBox = this.cropBox; if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
cropBox.left = cropBox.oldLeft;
} if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) {
cropBox.top = cropBox.oldTop;
} cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); this.limitCropBox(false, true); cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft);
cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop); if (options.movable && options.cropBoxMovable) { // Turn to move the canvas when the crop box is equal to the container
this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL);
} this.$cropBox.css({
width: cropBox.width,
height: cropBox.height,
left: cropBox.left,
top: cropBox.top
}); if (this.isCropped && this.isLimited) {
this.limitCanvas(true, true);
} if (!this.isDisabled) {
this.output();
}
}, output: function () {
this.preview(); if (this.isCompleted) {
this.trigger(EVENT_CROP, this.getData());
}
}, initPreview: function () {
var crossOrigin = getCrossOrigin(this.crossOrigin);
var url = crossOrigin ? this.crossOriginUrl : this.url;
var $clone2; this.$preview = $(this.options.preview);
this.$clone2 = $clone2 = $('<img' + crossOrigin + ' src="' + url + '">');
this.$viewBox.html($clone2);
this.$preview.each(function () {
var $this = $(this); // Save the original size for recover
$this.data(DATA_PREVIEW, {
width: $this.width(),
height: $this.height(),
html: $this.html()
}); /**
* Override img element styles
* Add `display:block` to avoid margin top issue
* (Occur only when margin-top <= -height)
*/
$this.html(
'<img' + crossOrigin + ' src="' + url + '" style="' +
'display:block;width:100%;height:auto;' +
'min-width:0!important;min-height:0!important;' +
'max-width:none!important;max-height:none!important;' +
'image-orientation:0deg!important;">'
);
});
}, resetPreview: function () {
this.$preview.each(function () {
var $this = $(this);
var data = $this.data(DATA_PREVIEW); $this.css({
width: data.width,
height: data.height
}).html(data.html).removeData(DATA_PREVIEW);
});
}, preview: function () {
var image = this.image;
var canvas = this.canvas;
var cropBox = this.cropBox;
var cropBoxWidth = cropBox.width;
var cropBoxHeight = cropBox.height;
var width = image.width;
var height = image.height;
var left = cropBox.left - canvas.left - image.left;
var top = cropBox.top - canvas.top - image.top; if (!this.isCropped || this.isDisabled) {
return;
} this.$clone2.css({
width: width,
height: height,
marginLeft: -left,
marginTop: -top,
transform: getTransform(image)
}); this.$preview.each(function () {
var $this = $(this);
var data = $this.data(DATA_PREVIEW);
var originalWidth = data.width;
var originalHeight = data.height;
var newWidth = originalWidth;
var newHeight = originalHeight;
var ratio = 1; if (cropBoxWidth) {
ratio = originalWidth / cropBoxWidth;
newHeight = cropBoxHeight * ratio;
} if (cropBoxHeight && newHeight > originalHeight) {
ratio = originalHeight / cropBoxHeight;
newWidth = cropBoxWidth * ratio;
newHeight = originalHeight;
} $this.css({
width: newWidth,
height: newHeight
}).find('img').css({
width: width * ratio,
height: height * ratio,
marginLeft: -left * ratio,
marginTop: -top * ratio,
transform: getTransform(image)
});
});
}, bind: function () {
var options = this.options;
var $this = this.$element;
var $cropper = this.$cropper; if ($.isFunction(options.cropstart)) {
$this.on(EVENT_CROP_START, options.cropstart);
} if ($.isFunction(options.cropmove)) {
$this.on(EVENT_CROP_MOVE, options.cropmove);
} if ($.isFunction(options.cropend)) {
$this.on(EVENT_CROP_END, options.cropend);
} if ($.isFunction(options.crop)) {
$this.on(EVENT_CROP, options.crop);
} if ($.isFunction(options.zoom)) {
$this.on(EVENT_ZOOM, options.zoom);
} $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this)); if (options.zoomable && options.zoomOnWheel) {
$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
} if (options.toggleDragModeOnDblclick) {
$cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
} $document.
on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))).
on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this))); if (options.responsive) {
$window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
}
}, unbind: function () {
var options = this.options;
var $this = this.$element;
var $cropper = this.$cropper; if ($.isFunction(options.cropstart)) {
$this.off(EVENT_CROP_START, options.cropstart);
} if ($.isFunction(options.cropmove)) {
$this.off(EVENT_CROP_MOVE, options.cropmove);
} if ($.isFunction(options.cropend)) {
$this.off(EVENT_CROP_END, options.cropend);
} if ($.isFunction(options.crop)) {
$this.off(EVENT_CROP, options.crop);
} if ($.isFunction(options.zoom)) {
$this.off(EVENT_ZOOM, options.zoom);
} $cropper.off(EVENT_MOUSE_DOWN, this.cropStart); if (options.zoomable && options.zoomOnWheel) {
$cropper.off(EVENT_WHEEL, this.wheel);
} if (options.toggleDragModeOnDblclick) {
$cropper.off(EVENT_DBLCLICK, this.dblclick);
} $document.
off(EVENT_MOUSE_MOVE, this._cropMove).
off(EVENT_MOUSE_UP, this._cropEnd); if (options.responsive) {
$window.off(EVENT_RESIZE, this._resize);
}
}, resize: function () {
var restore = this.options.restore;
var $container = this.$container;
var container = this.container;
var canvasData;
var cropBoxData;
var ratio; // Check `container` is necessary for IE8
if (this.isDisabled || !container) {
return;
} ratio = $container.width() / container.width; // Resize when width changed or height changed
if (ratio !== 1 || $container.height() !== container.height) {
if (restore) {
canvasData = this.getCanvasData();
cropBoxData = this.getCropBoxData();
} this.render(); if (restore) {
this.setCanvasData($.each(canvasData, function (i, n) {
canvasData[i] = n * ratio;
}));
this.setCropBoxData($.each(cropBoxData, function (i, n) {
cropBoxData[i] = n * ratio;
}));
}
}
}, dblclick: function () {
if (this.isDisabled) {
return;
} if (this.$dragBox.hasClass(CLASS_CROP)) {
this.setDragMode(ACTION_MOVE);
} else {
this.setDragMode(ACTION_CROP);
}
}, wheel: function (event) {
var e = event.originalEvent || event;
var ratio = num(this.options.wheelZoomRatio) || 0.1;
var delta = 1; if (this.isDisabled) {
return;
} event.preventDefault(); // Limit wheel speed to prevent zoom too fast
if (this.wheeling) {
return;
} this.wheeling = true; setTimeout($.proxy(function () {
this.wheeling = false;
}, this), 50); if (e.deltaY) {
delta = e.deltaY > 0 ? 1 : -1;
} else if (e.wheelDelta) {
delta = -e.wheelDelta / 120;
} else if (e.detail) {
delta = e.detail > 0 ? 1 : -1;
} this.zoom(-delta * ratio, event);
}, cropStart: function (event) {
var options = this.options;
var originalEvent = event.originalEvent;
var touches = originalEvent && originalEvent.touches;
var e = event;
var touchesLength;
var action; if (this.isDisabled) {
return;
} if (touches) {
touchesLength = touches.length; if (touchesLength > 1) {
if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
e = touches[1];
this.startX2 = e.pageX;
this.startY2 = e.pageY;
action = ACTION_ZOOM;
} else {
return;
}
} e = touches[0];
} action = action || $(e.target).data(DATA_ACTION); if (REGEXP_ACTIONS.test(action)) {
if (this.trigger(EVENT_CROP_START, {
originalEvent: originalEvent,
action: action
}).isDefaultPrevented()) {
return;
} event.preventDefault(); this.action = action;
this.cropping = false; // IE8 has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
// IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
this.startX = e.pageX || originalEvent && originalEvent.pageX;
this.startY = e.pageY || originalEvent && originalEvent.pageY; if (action === ACTION_CROP) {
this.cropping = true;
this.$dragBox.addClass(CLASS_MODAL);
}
}
}, cropMove: function (event) {
var options = this.options;
var originalEvent = event.originalEvent;
var touches = originalEvent && originalEvent.touches;
var e = event;
var action = this.action;
var touchesLength; if (this.isDisabled) {
return;
} if (touches) {
touchesLength = touches.length; if (touchesLength > 1) {
if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
e = touches[1];
this.endX2 = e.pageX;
this.endY2 = e.pageY;
} else {
return;
}
} e = touches[0];
} if (action) {
if (this.trigger(EVENT_CROP_MOVE, {
originalEvent: originalEvent,
action: action
}).isDefaultPrevented()) {
return;
} event.preventDefault(); this.endX = e.pageX || originalEvent && originalEvent.pageX;
this.endY = e.pageY || originalEvent && originalEvent.pageY; this.change(e.shiftKey, action === ACTION_ZOOM ? event : null);
}
}, cropEnd: function (event) {
var originalEvent = event.originalEvent;
var action = this.action; if (this.isDisabled) {
return;
} if (action) {
event.preventDefault(); if (this.cropping) {
this.cropping = false;
this.$dragBox.toggleClass(CLASS_MODAL, this.isCropped && this.options.modal);
} this.action = ''; this.trigger(EVENT_CROP_END, {
originalEvent: originalEvent,
action: action
});
}
}, change: function (shiftKey, event) {
var options = this.options;
var aspectRatio = options.aspectRatio;
var action = this.action;
var container = this.container;
var canvas = this.canvas;
var cropBox = this.cropBox;
var width = cropBox.width;
var height = cropBox.height;
var left = cropBox.left;
var top = cropBox.top;
var right = left + width;
var bottom = top + height;
var minLeft = 0;
var minTop = 0;
var maxWidth = container.width;
var maxHeight = container.height;
var renderable = true;
var offset;
var range; // Locking aspect ratio in "free mode" by holding shift key (#259)
if (!aspectRatio && shiftKey) {
aspectRatio = width && height ? width / height : 1;
} if (this.isLimited) {
minLeft = cropBox.minLeft;
minTop = cropBox.minTop;
maxWidth = minLeft + min(container.width, canvas.width, canvas.left + canvas.width);
maxHeight = minTop + min(container.height, canvas.height, canvas.top + canvas.height);
} range = {
x: this.endX - this.startX,
y: this.endY - this.startY
}; if (aspectRatio) {
range.X = range.y * aspectRatio;
range.Y = range.x / aspectRatio;
} switch (action) {
// Move crop box
case ACTION_ALL:
left += range.x;
top += range.y;
break; // Resize crop box
case ACTION_EAST:
if (range.x >= 0 && (right >= maxWidth || aspectRatio &&
(top <= minTop || bottom >= maxHeight))) { renderable = false;
break;
} width += range.x; if (aspectRatio) {
height = width / aspectRatio;
top -= range.Y / 2;
} if (width < 0) {
action = ACTION_WEST;
width = 0;
} break; case ACTION_NORTH:
if (range.y <= 0 && (top <= minTop || aspectRatio &&
(left <= minLeft || right >= maxWidth))) { renderable = false;
break;
} height -= range.y;
top += range.y; if (aspectRatio) {
width = height * aspectRatio;
left += range.X / 2;
} if (height < 0) {
action = ACTION_SOUTH;
height = 0;
} break; case ACTION_WEST:
if (range.x <= 0 && (left <= minLeft || aspectRatio &&
(top <= minTop || bottom >= maxHeight))) { renderable = false;
break;
} width -= range.x;
left += range.x; if (aspectRatio) {
height = width / aspectRatio;
top += range.Y / 2;
} if (width < 0) {
action = ACTION_EAST;
width = 0;
} break; case ACTION_SOUTH:
if (range.y >= 0 && (bottom >= maxHeight || aspectRatio &&
(left <= minLeft || right >= maxWidth))) { renderable = false;
break;
} height += range.y; if (aspectRatio) {
width = height * aspectRatio;
left -= range.X / 2;
} if (height < 0) {
action = ACTION_NORTH;
height = 0;
} break; case ACTION_NORTH_EAST:
if (aspectRatio) {
if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
renderable = false;
break;
} height -= range.y;
top += range.y;
width = height * aspectRatio;
} else {
if (range.x >= 0) {
if (right < maxWidth) {
width += range.x;
} else if (range.y <= 0 && top <= minTop) {
renderable = false;
}
} else {
width += range.x;
} if (range.y <= 0) {
if (top > minTop) {
height -= range.y;
top += range.y;
}
} else {
height -= range.y;
top += range.y;
}
} if (width < 0 && height < 0) {
action = ACTION_SOUTH_WEST;
height = 0;
width = 0;
} else if (width < 0) {
action = ACTION_NORTH_WEST;
width = 0;
} else if (height < 0) {
action = ACTION_SOUTH_EAST;
height = 0;
} break; case ACTION_NORTH_WEST:
if (aspectRatio) {
if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
renderable = false;
break;
} height -= range.y;
top += range.y;
width = height * aspectRatio;
left += range.X;
} else {
if (range.x <= 0) {
if (left > minLeft) {
width -= range.x;
left += range.x;
} else if (range.y <= 0 && top <= minTop) {
renderable = false;
}
} else {
width -= range.x;
left += range.x;
} if (range.y <= 0) {
if (top > minTop) {
height -= range.y;
top += range.y;
}
} else {
height -= range.y;
top += range.y;
}
} if (width < 0 && height < 0) {
action = ACTION_SOUTH_EAST;
height = 0;
width = 0;
} else if (width < 0) {
action = ACTION_NORTH_EAST;
width = 0;
} else if (height < 0) {
action = ACTION_SOUTH_WEST;
height = 0;
} break; case ACTION_SOUTH_WEST:
if (aspectRatio) {
if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
renderable = false;
break;
} width -= range.x;
left += range.x;
height = width / aspectRatio;
} else {
if (range.x <= 0) {
if (left > minLeft) {
width -= range.x;
left += range.x;
} else if (range.y >= 0 && bottom >= maxHeight) {
renderable = false;
}
} else {
width -= range.x;
left += range.x;
} if (range.y >= 0) {
if (bottom < maxHeight) {
height += range.y;
}
} else {
height += range.y;
}
} if (width < 0 && height < 0) {
action = ACTION_NORTH_EAST;
height = 0;
width = 0;
} else if (width < 0) {
action = ACTION_SOUTH_EAST;
width = 0;
} else if (height < 0) {
action = ACTION_NORTH_WEST;
height = 0;
} break; case ACTION_SOUTH_EAST:
if (aspectRatio) {
if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
renderable = false;
break;
} width += range.x;
height = width / aspectRatio;
} else {
if (range.x >= 0) {
if (right < maxWidth) {
width += range.x;
} else if (range.y >= 0 && bottom >= maxHeight) {
renderable = false;
}
} else {
width += range.x;
} if (range.y >= 0) {
if (bottom < maxHeight) {
height += range.y;
}
} else {
height += range.y;
}
} if (width < 0 && height < 0) {
action = ACTION_NORTH_WEST;
height = 0;
width = 0;
} else if (width < 0) {
action = ACTION_SOUTH_WEST;
width = 0;
} else if (height < 0) {
action = ACTION_NORTH_EAST;
height = 0;
} break; // Move canvas
case ACTION_MOVE:
this.move(range.x, range.y);
renderable = false;
break; // Zoom canvas
case ACTION_ZOOM:
this.zoom((function (x1, y1, x2, y2) {
var z1 = sqrt(x1 * x1 + y1 * y1);
var z2 = sqrt(x2 * x2 + y2 * y2); return (z2 - z1) / z1;
})(
abs(this.startX - this.startX2),
abs(this.startY - this.startY2),
abs(this.endX - this.endX2),
abs(this.endY - this.endY2)
), event);
this.startX2 = this.endX2;
this.startY2 = this.endY2;
renderable = false;
break; // Create crop box
case ACTION_CROP:
if (!range.x || !range.y) {
renderable = false;
break;
} offset = this.$cropper.offset();
left = this.startX - offset.left;
top = this.startY - offset.top;
width = cropBox.minWidth;
height = cropBox.minHeight; if (range.x > 0) {
action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;
} else if (range.x < 0) {
left -= width;
action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;
} if (range.y < 0) {
top -= height;
} // Show the crop box if is hidden
if (!this.isCropped) {
this.$cropBox.removeClass(CLASS_HIDDEN);
this.isCropped = true; if (this.isLimited) {
this.limitCropBox(true, true);
}
} break; // No default
} if (renderable) {
cropBox.width = width;
cropBox.height = height;
cropBox.left = left;
cropBox.top = top;
this.action = action; this.renderCropBox();
} // Override
this.startX = this.endX;
this.startY = this.endY;
}, // Show the crop box manually
crop: function () {
if (!this.isBuilt || this.isDisabled) {
return;
} if (!this.isCropped) {
this.isCropped = true;
this.limitCropBox(true, true); if (this.options.modal) {
this.$dragBox.addClass(CLASS_MODAL);
} this.$cropBox.removeClass(CLASS_HIDDEN);
} this.setCropBoxData(this.initialCropBox);
}, // Reset the image and crop box to their initial states
reset: function () {
if (!this.isBuilt || this.isDisabled) {
return;
} this.image = $.extend({}, this.initialImage);
this.canvas = $.extend({}, this.initialCanvas);
this.cropBox = $.extend({}, this.initialCropBox); this.renderCanvas(); if (this.isCropped) {
this.renderCropBox();
}
}, // Clear the crop box
clear: function () {
if (!this.isCropped || this.isDisabled) {
return;
} $.extend(this.cropBox, {
left: 0,
top: 0,
width: 0,
height: 0
}); this.isCropped = false;
this.renderCropBox(); this.limitCanvas(true, true); // Render canvas after crop box rendered
this.renderCanvas(); this.$dragBox.removeClass(CLASS_MODAL);
this.$cropBox.addClass(CLASS_HIDDEN);
}, /**
* Replace the image's src and rebuild the cropper
*
* @param {String} url
* @param {Boolean} onlyColorChanged (optional)
*/
replace: function (url, onlyColorChanged) {
if (!this.isDisabled && url) {
if (this.isImg) {
this.$element.attr('src', url);
} if (onlyColorChanged) {
this.url = url;
this.$clone.attr('src', url); if (this.isBuilt) {
this.$preview.find('img').add(this.$clone2).attr('src', url);
}
} else {
if (this.isImg) {
this.isReplaced = true;
} // Clear previous data
this.options.data = null;
this.load(url);
}
}
}, // Enable (unfreeze) the cropper
enable: function () {
if (this.isBuilt) {
this.isDisabled = false;
this.$cropper.removeClass(CLASS_DISABLED);
}
}, // Disable (freeze) the cropper
disable: function () {
if (this.isBuilt) {
this.isDisabled = true;
this.$cropper.addClass(CLASS_DISABLED);
}
}, // Destroy the cropper and remove the instance from the image
destroy: function () {
var $this = this.$element; if (this.isLoaded) {
if (this.isImg && this.isReplaced) {
$this.attr('src', this.originalUrl);
} this.unbuild();
$this.removeClass(CLASS_HIDDEN);
} else {
if (this.isImg) {
$this.off(EVENT_LOAD, this.start);
} else if (this.$clone) {
this.$clone.remove();
}
} $this.removeData(NAMESPACE);
}, /**
* Move the canvas with relative offsets
*
* @param {Number} offsetX
* @param {Number} offsetY (optional)
*/
move: function (offsetX, offsetY) {
var canvas = this.canvas; this.moveTo(
isUndefined(offsetX) ? offsetX : canvas.left + num(offsetX),
isUndefined(offsetY) ? offsetY : canvas.top + num(offsetY)
);
}, /**
* Move the canvas to an absolute point
*
* @param {Number} x
* @param {Number} y (optional)
*/
moveTo: function (x, y) {
var canvas = this.canvas;
var isChanged = false; // If "y" is not present, its default value is "x"
if (isUndefined(y)) {
y = x;
} x = num(x);
y = num(y); if (this.isBuilt && !this.isDisabled && this.options.movable) {
if (isNumber(x)) {
canvas.left = x;
isChanged = true;
} if (isNumber(y)) {
canvas.top = y;
isChanged = true;
} if (isChanged) {
this.renderCanvas(true);
}
}
}, /**
* Zoom the canvas with a relative ratio
*
* @param {Number} ratio
* @param {jQuery Event} _event (private)
*/
zoom: function (ratio, _event) {
var canvas = this.canvas; ratio = num(ratio); if (ratio < 0) {
ratio = 1 / (1 - ratio);
} else {
ratio = 1 + ratio;
} this.zoomTo(canvas.width * ratio / canvas.naturalWidth, _event);
}, /**
* Zoom the canvas to an absolute ratio
*
* @param {Number} ratio
* @param {jQuery Event} _event (private)
*/
zoomTo: function (ratio, _event) {
var options = this.options;
var canvas = this.canvas;
var width = canvas.width;
var height = canvas.height;
var naturalWidth = canvas.naturalWidth;
var naturalHeight = canvas.naturalHeight;
var originalEvent;
var newWidth;
var newHeight;
var offset;
var center; ratio = num(ratio); if (ratio >= 0 && this.isBuilt && !this.isDisabled && options.zoomable) {
newWidth = naturalWidth * ratio;
newHeight = naturalHeight * ratio; if (_event) {
originalEvent = _event.originalEvent;
} if (this.trigger(EVENT_ZOOM, {
originalEvent: originalEvent,
oldRatio: width / naturalWidth,
ratio: newWidth / naturalWidth
}).isDefaultPrevented()) {
return;
} if (originalEvent) {
offset = this.$cropper.offset();
center = originalEvent.touches ? getTouchesCenter(originalEvent.touches) : {
pageX: _event.pageX || originalEvent.pageX || 0,
pageY: _event.pageY || originalEvent.pageY || 0
}; // Zoom from the triggering point of the event
canvas.left -= (newWidth - width) * (
((center.pageX - offset.left) - canvas.left) / width
);
canvas.top -= (newHeight - height) * (
((center.pageY - offset.top) - canvas.top) / height
);
} else { // Zoom from the center of the canvas
canvas.left -= (newWidth - width) / 2;
canvas.top -= (newHeight - height) / 2;
} canvas.width = newWidth;
canvas.height = newHeight;
this.renderCanvas(true);
}
}, /**
* Rotate the canvas with a relative degree
*
* @param {Number} degree
*/
rotate: function (degree) {
this.rotateTo((this.image.rotate || 0) + num(degree));
}, /**
* Rotate the canvas to an absolute degree
* https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate()
*
* @param {Number} degree
*/
rotateTo: function (degree) {
degree = num(degree); if (isNumber(degree) && this.isBuilt && !this.isDisabled && this.options.rotatable) {
this.image.rotate = degree % 360;
this.isRotated = true;
this.renderCanvas(true);
}
}, /**
* Scale the image
* https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale()
*
* @param {Number} scaleX
* @param {Number} scaleY (optional)
*/
scale: function (scaleX, scaleY) {
var image = this.image;
var isChanged = false; // If "scaleY" is not present, its default value is "scaleX"
if (isUndefined(scaleY)) {
scaleY = scaleX;
} scaleX = num(scaleX);
scaleY = num(scaleY); if (this.isBuilt && !this.isDisabled && this.options.scalable) {
if (isNumber(scaleX)) {
image.scaleX = scaleX;
isChanged = true;
} if (isNumber(scaleY)) {
image.scaleY = scaleY;
isChanged = true;
} if (isChanged) {
this.renderImage(true);
}
}
}, /**
* Scale the abscissa of the image
*
* @param {Number} scaleX
*/
scaleX: function (scaleX) {
var scaleY = this.image.scaleY; this.scale(scaleX, isNumber(scaleY) ? scaleY : 1);
}, /**
* Scale the ordinate of the image
*
* @param {Number} scaleY
*/
scaleY: function (scaleY) {
var scaleX = this.image.scaleX; this.scale(isNumber(scaleX) ? scaleX : 1, scaleY);
}, /**
* Get the cropped area position and size data (base on the original image)
*
* @param {Boolean} isRounded (optional)
* @return {Object} data
*/
getData: function (isRounded) {
var options = this.options;
var image = this.image;
var canvas = this.canvas;
var cropBox = this.cropBox;
var ratio;
var data; if (this.isBuilt && this.isCropped) {
data = {
x: cropBox.left - canvas.left,
y: cropBox.top - canvas.top,
width: cropBox.width,
height: cropBox.height
}; ratio = image.width / image.naturalWidth; $.each(data, function (i, n) {
n = n / ratio;
data[i] = isRounded ? round(n) : n;
}); } else {
data = {
x: 0,
y: 0,
width: 0,
height: 0
};
} if (options.rotatable) {
data.rotate = image.rotate || 0;
} if (options.scalable) {
data.scaleX = image.scaleX || 1;
data.scaleY = image.scaleY || 1;
} return data;
}, /**
* Set the cropped area position and size with new data
*
* @param {Object} data
*/
setData: function (data) {
var options = this.options;
var image = this.image;
var canvas = this.canvas;
var cropBoxData = {};
var isRotated;
var isScaled;
var ratio; if ($.isFunction(data)) {
data = data.call(this.element);
} if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
if (options.rotatable) {
if (isNumber(data.rotate) && data.rotate !== image.rotate) {
image.rotate = data.rotate;
this.isRotated = isRotated = true;
}
} if (options.scalable) {
if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) {
image.scaleX = data.scaleX;
isScaled = true;
} if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) {
image.scaleY = data.scaleY;
isScaled = true;
}
} if (isRotated) {
this.renderCanvas();
} else if (isScaled) {
this.renderImage();
} ratio = image.width / image.naturalWidth; if (isNumber(data.x)) {
cropBoxData.left = data.x * ratio + canvas.left;
} if (isNumber(data.y)) {
cropBoxData.top = data.y * ratio + canvas.top;
} if (isNumber(data.width)) {
cropBoxData.width = data.width * ratio;
} if (isNumber(data.height)) {
cropBoxData.height = data.height * ratio;
} this.setCropBoxData(cropBoxData);
}
}, /**
* Get the container size data
*
* @return {Object} data
*/
getContainerData: function () {
return this.isBuilt ? this.container : {};
}, /**
* Get the image position and size data
*
* @return {Object} data
*/
getImageData: function () {
return this.isLoaded ? this.image : {};
}, /**
* Get the canvas position and size data
*
* @return {Object} data
*/
getCanvasData: function () {
var canvas = this.canvas;
var data = {}; if (this.isBuilt) {
$.each([
'left',
'top',
'width',
'height',
'naturalWidth',
'naturalHeight'
], function (i, n) {
data[n] = canvas[n];
});
} return data;
}, /**
* Set the canvas position and size with new data
*
* @param {Object} data
*/
setCanvasData: function (data) {
var canvas = this.canvas;
var aspectRatio = canvas.aspectRatio; if ($.isFunction(data)) {
data = data.call(this.$element);
} if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
if (isNumber(data.left)) {
canvas.left = data.left;
} if (isNumber(data.top)) {
canvas.top = data.top;
} if (isNumber(data.width)) {
canvas.width = data.width;
canvas.height = data.width / aspectRatio;
} else if (isNumber(data.height)) {
canvas.height = data.height;
canvas.width = data.height * aspectRatio;
} this.renderCanvas(true);
}
}, /**
* Get the crop box position and size data
*
* @return {Object} data
*/
getCropBoxData: function () {
var cropBox = this.cropBox;
var data; if (this.isBuilt && this.isCropped) {
data = {
left: cropBox.left,
top: cropBox.top,
width: cropBox.width,
height: cropBox.height
};
} return data || {};
}, /**
* Set the crop box position and size with new data
*
* @param {Object} data
*/
setCropBoxData: function (data) {
var cropBox = this.cropBox;
var aspectRatio = this.options.aspectRatio;
var isWidthChanged;
var isHeightChanged; if ($.isFunction(data)) {
data = data.call(this.$element);
} if (this.isBuilt && this.isCropped && !this.isDisabled && $.isPlainObject(data)) { if (isNumber(data.left)) {
cropBox.left = data.left;
} if (isNumber(data.top)) {
cropBox.top = data.top;
} if (isNumber(data.width)) {
isWidthChanged = true;
cropBox.width = data.width;
} if (isNumber(data.height)) {
isHeightChanged = true;
cropBox.height = data.height;
} if (aspectRatio) {
if (isWidthChanged) {
cropBox.height = cropBox.width / aspectRatio;
} else if (isHeightChanged) {
cropBox.width = cropBox.height * aspectRatio;
}
} this.renderCropBox();
}
}, /**
* Get a canvas drawn the cropped image
*
* @param {Object} options (optional)
* @return {HTMLCanvasElement} canvas
*/
getCroppedCanvas: function (options) {
var originalWidth;
var originalHeight;
var canvasWidth;
var canvasHeight;
var scaledWidth;
var scaledHeight;
var scaledRatio;
var aspectRatio;
var canvas;
var context;
var data; if (!this.isBuilt || !SUPPORT_CANVAS) {
return;
} if (!this.isCropped) {
return getSourceCanvas(this.$clone[0], this.image);
} if (!$.isPlainObject(options)) {
options = {};
} data = this.getData();
originalWidth = data.width;
originalHeight = data.height;
aspectRatio = originalWidth / originalHeight; if ($.isPlainObject(options)) {
scaledWidth = options.width;
scaledHeight = options.height; if (scaledWidth) {
scaledHeight = scaledWidth / aspectRatio;
scaledRatio = scaledWidth / originalWidth;
} else if (scaledHeight) {
scaledWidth = scaledHeight * aspectRatio;
scaledRatio = scaledHeight / originalHeight;
}
} // The canvas element will use `Math.floor` on a float number, so floor first
canvasWidth = floor(scaledWidth || originalWidth);
canvasHeight = floor(scaledHeight || originalHeight); canvas = $('<canvas>')[0];
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context = canvas.getContext('2d'); if (options.fillColor) {
context.fillStyle = options.fillColor;
context.fillRect(0, 0, canvasWidth, canvasHeight);
} // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
context.drawImage.apply(context, (function () {
var source = getSourceCanvas(this.$clone[0], this.image);
var sourceWidth = source.width;
var sourceHeight = source.height;
var canvas = this.canvas;
var params = [source]; // Source canvas
var srcX = data.x + canvas.naturalWidth * (abs(data.scaleX || 1) - 1) / 2;
var srcY = data.y + canvas.naturalHeight * (abs(data.scaleY || 1) - 1) / 2;
var srcWidth;
var srcHeight; // Destination canvas
var dstX;
var dstY;
var dstWidth;
var dstHeight; if (srcX <= -originalWidth || srcX > sourceWidth) {
srcX = srcWidth = dstX = dstWidth = 0;
} else if (srcX <= 0) {
dstX = -srcX;
srcX = 0;
srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX);
} else if (srcX <= sourceWidth) {
dstX = 0;
srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX);
} if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) {
srcY = srcHeight = dstY = dstHeight = 0;
} else if (srcY <= 0) {
dstY = -srcY;
srcY = 0;
srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY);
} else if (srcY <= sourceHeight) {
dstY = 0;
srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
} // All the numerical parameters should be integer for `drawImage` (#476)
params.push(floor(srcX), floor(srcY), floor(srcWidth), floor(srcHeight)); // Scale destination sizes
if (scaledRatio) {
dstX *= scaledRatio;
dstY *= scaledRatio;
dstWidth *= scaledRatio;
dstHeight *= scaledRatio;
} // Avoid "IndexSizeError" in IE and Firefox
if (dstWidth > 0 && dstHeight > 0) {
params.push(floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));
} return params;
}).call(this)); return canvas;
}, /**
* Change the aspect ratio of the crop box
*
* @param {Number} aspectRatio
*/
setAspectRatio: function (aspectRatio) {
var options = this.options; if (!this.isDisabled && !isUndefined(aspectRatio)) { // 0 -> NaN
options.aspectRatio = max(0, aspectRatio) || NaN; if (this.isBuilt) {
this.initCropBox(); if (this.isCropped) {
this.renderCropBox();
}
}
}
}, /**
* Change the drag mode
*
* @param {String} mode (optional)
*/
setDragMode: function (mode) {
var options = this.options;
var croppable;
var movable; if (this.isLoaded && !this.isDisabled) {
croppable = mode === ACTION_CROP;
movable = options.movable && mode === ACTION_MOVE;
mode = (croppable || movable) ? mode : ACTION_NONE; this.$dragBox.
data(DATA_ACTION, mode).
toggleClass(CLASS_CROP, croppable).
toggleClass(CLASS_MOVE, movable); if (!options.cropBoxMovable) { // Sync drag mode to crop box when it is not movable(#300)
this.$face.
data(DATA_ACTION, mode).
toggleClass(CLASS_CROP, croppable).
toggleClass(CLASS_MOVE, movable);
}
}
}
}; Cropper.DEFAULTS = { // Define the view mode of the cropper
viewMode: 0, // 0, 1, 2, 3 // Define the dragging mode of the cropper
dragMode: 'crop', // 'crop', 'move' or 'none' // Define the aspect ratio of the crop box
aspectRatio: NaN, // An object with the previous cropping result data
data: null, // A jQuery selector for adding extra containers to preview
preview: '', // Re-render the cropper when resize the window
responsive: true, // Restore the cropped area after resize the window
restore: true, // Check if the current image is a cross-origin image
checkCrossOrigin: true, // Check the current image's Exif Orientation information
checkOrientation: true, // Show the black modal
modal: true, // Show the dashed lines for guiding
guides: true, // Show the center indicator for guiding
center: true, // Show the white modal to highlight the crop box
highlight: true, // Show the grid background
background: true, // Enable to crop the image automatically when initialize
autoCrop: true, // Define the percentage of automatic cropping area when initializes
autoCropArea: 0.8, // Enable to move the image
movable: true, // Enable to rotate the image
rotatable: true, // Enable to scale the image
scalable: true, // Enable to zoom the image
zoomable: true, // Enable to zoom the image by dragging touch
zoomOnTouch: true, // Enable to zoom the image by wheeling mouse
zoomOnWheel: true, // Define zoom ratio when zoom the image by wheeling mouse
wheelZoomRatio: 0.1, // Enable to move the crop box
cropBoxMovable: true, // Enable to resize the crop box
cropBoxResizable: true, // Toggle drag mode between "crop" and "move" when click twice on the cropper
toggleDragModeOnDblclick: true, // Size limitation
minCanvasWidth: 0,
minCanvasHeight: 0,
minCropBoxWidth: 0,
minCropBoxHeight: 0,
minContainerWidth: 200,
minContainerHeight: 100, // Shortcuts of events
build: null,
built: null,
cropstart: null,
cropmove: null,
cropend: null,
crop: null,
zoom: null
}; Cropper.setDefaults = function (options) {
$.extend(Cropper.DEFAULTS, options);
}; Cropper.TEMPLATE = (
'<div class="cropper-container">' +
'<div class="cropper-wrap-box">' +
'<div class="cropper-canvas"></div>' +
'</div>' +
'<div class="cropper-drag-box"></div>' + '</div>'
); // Save the other cropper
Cropper.other = $.fn.cropper; // Register as jQuery plugin
$.fn.cropper = function (option) {
var args = toArray(arguments, 1);
var result; this.each(function () {
var $this = $(this);
var data = $this.data(NAMESPACE);
var options;
var fn; if (!data) {
if (/destroy/.test(option)) {
return;
} options = $.extend({}, $this.data(), $.isPlainObject(option) && option);
$this.data(NAMESPACE, (data = new Cropper(this, options)));
} if (typeof option === 'string' && $.isFunction(fn = data[option])) {
result = fn.apply(data, args);
}
}); return isUndefined(result) ? this : result;
}; $.fn.cropper.Constructor = Cropper;
$.fn.cropper.setDefaults = Cropper.setDefaults; // No conflict
$.fn.cropper.noConflict = function () {
$.fn.cropper = Cropper.other;
return this;
}; });

完成。

HTML5 canvas处理图片的各种效果,包括放大缩小涂鸦等的更多相关文章

  1. 如何使用 HTML5 Canvas 制作水波纹效果

    今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果.水波效果以图片为背景,点击图片任意位置都会触发.有时候,我们使用普通的 Javasc ...

  2. 基于HTML5 Canvas可撕裂布料效果

    分享一款布料效果的 HTML5 Canvas 应用演示,效果逼真.你会看到,借助 Canvas 的强大绘图和动画功能,只需很少的代码就能实现让您屏息凝神的效果. 在线预览   源码下载 实现的代码. ...

  3. HTML5 canvas炫酷棱镜效果的幻灯片特效

    这是一款效果很炫酷华丽的HTML5 canvas带棱镜效果的幻灯片特效. 这个特效在每个幻灯片的前面放置一个图形.并将图形制作为三棱镜效果.它底下的幻灯片图片会被"折射"到棱镜上面 ...

  4. 八大疯狂的HTML5 Canvas及WebGL动画效果——8 CRAZY ANIMATIONS WITH WEBGL AND HTML5 CANVAS【收藏】

    HTML5, WebGL and Javascript have changed the way animation used to be. Past few years, we can only a ...

  5. [js高手之路]html5 canvas动画教程 - 下雪效果

    利用canvas,实现一个下雪的效果,我们先预览下效果: 我们先分析下这个效果: 1,随机产生雪花 2,雪花的产生不是同时产生,而是有先后顺序的 3,雪花怎么表示 4,怎么源源不断的下雪 5,雪花有大 ...

  6. 基于HTML5 Canvas 实现的 Loading 效果

    Sonic.js 是一个很小的 JavaScript 类,用于创建基于 HTML5 画布的加载图像.更强大的是 Sonic.js 还提供了基于现成的例子的创建工具,可以帮助你实现更多自定义的(Load ...

  7. HTML5 Canvas绘制的下雪效果

    在HTML页面的HEAD区域直接引入snow.js即可,如下:<script type="text/javascript" src="js/snow.js" ...

  8. HTML5:使用Canvas和Input range控件放大缩小图片,剪裁,并上传图片

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. 基于HTML5 Canvas生成粒子效果的人物头像

    前面我们分享过一个HTML5 Canvas实现的图像马赛克模糊效果,HTML5处理图片真的非常简单.今天我们要再利用HTML5 Canvas实现一个粒子效果的人物头像,你可以任意选择一张头像图片,接下 ...

随机推荐

  1. iOS用户信息单例的创建

    UserInfo.h + (UserInfo *) sharedInstance; UserInfo.m #import "UserInfo.h" static UserInfo ...

  2. GridView 实现LinkButton下载文件/附件

    <asp:TemplateField > <ItemTemplate> <asp:LinkButton ID="lbtnDownFile" runat ...

  3. 转C#窗体无法接受Keydown事件

    问题一描述:当新建一个窗体时,添加KeyDown事件后,会正常处理,但是当添加有控件时,比如Button,TextBox,不会触发窗体的KeyDown事件,也没有调用KeyDown事件的处理程序. 原 ...

  4. Linux从零单排(二):setuptools、pip、anaconda2的环境配置

    为了更方便的使用Python的类库,需要进行相应的配置 (一)setuptools的配置 1.setuptools的下载 命令行输入wget https://pypi.python.org/packa ...

  5. Oracle 索引创建、表分区

    --EAF_WORKFLOWSTEP 表创建 CREATE TABLE EAF_WORKFLOWSTEP ( ) NOT NULL PRIMARY KEY USING INDEX TABLESPACE ...

  6. Reflection应用场景-利用反射机制将表单数据自动填充到JavaBean中

  7. C/C++ 结构体 指针 简单输入输出

    #include <stdio.h> #include <stdlib.h> struct student{ int num; ]; double dec; }; int ma ...

  8. 【原创】linux 批量清空文本内容

    清空所有PHP文件 find . -name '*.php'|xargs sed -i '1,$d' 清空所有文件 find . -type f|xargs sed -i '1,$d'

  9. <<小朋友的数字>>核心代码

    for(i=l;i<=n;i++) { a[i]=read(); t=t+a[i]; if (t>maxn) maxn=t if( t<0) t=0; b[i]=maxn; }

  10. 阿里云推荐码 hut29f

    阿里云 推荐码 hut29f,适用于新手首次购买.