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. js常用关键字和函数

    document.createElement("div"): 创建一个div元素申明一个变量 document.body.appendChild(div);   将创建好的div添 ...

  2. C#注解属性的感想一:

    C#当中Attribute(中文注解属性)已经知道这个概念已经很久很久了,不过悲剧的是在实际项目当中重来没有用它来做过什么东西,以致对它的理解总是很浅薄,更谈不上如何在实际项目中运用它.最近在学习&l ...

  3. Issue 5:Hadoop博客系列转载

    Alex 的 Hadoop 菜鸟教程: 第1课 hadoop体系介绍 Alex 的 Hadoop 菜鸟教程: 第2课 hadoop 安装教程 (CentOS6 CDH分支 yum方式) Alex 的 ...

  4. VC6.0中友元函数无法访问类私有成员的解决办法

    举个例子: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #inclu ...

  5. 在Eclipse 中使用tomcat8

    最新版本的Eclipse让人不支持 Tomcat 8,该方法让Eclipse能使用Tomcat8 第一步:下载最新版本Eclipse for Java EE 第二步:到WTP downloads pa ...

  6. struts2:字段校验和非字段校验代码示例

    一.为什么要使用struts2的validate验证框架 :使用struts2的验证框架,能够提高客户端提交的数据的安全性.通过验证,确保保存进数据库的信息是正确的 二.使用struts2的valid ...

  7. Javascript模块化编程(三):require.js的用法(转)

    这个系列的第一部分和第二部分,介绍了Javascript模块原型和理论概念,今天介绍如何将它们用于实战. 我采用的是一个非常流行的库require.js. 一.为什么要用require.js? 最早的 ...

  8. liunx 远程拷贝到本地

    此句在本地git bash 执行,就能拷贝远程的目录 scp -r  userName@remote:/var/www/views/log/*.* ~/Desktop

  9. JAVA基本类库介绍

    我们曾经讲过,Java已经为编程者编制了许多类,这些类已经经过测试,基本上不存在错误,这些类都是我们编程的基础.如果不利用这些已存在的类,我们的 编程工作将变得异常复杂,所以我们应尽可能多的掌握Jav ...

  10. js字符串和正则表达式中的match、replace、exec等函数详解

    正则并不是经常使用,而正则和字符串之间的函数关系又错综复杂,谁是谁的函数,又是怎么样的一种结果,往往我们是看一遍忘一遍,对此我是头疼不已,感觉自己是个笨蛋^_^. 为了以后不再查文档,特此把常用的函数 ...