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. 转C#窗体无法接受Keydown事件

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

  2. javascript中原型(prototype)与原型链

    javascript是一门动态语言(动态语言Dynamic Programming Language:动态类型语言,意思就是类型的检查是在运行时做的,也就是常说的“弱类型”语言),没有类的概念,有cl ...

  3. Android新组件CardView

    Android L以后,新增了一个CardView组件,Google官方应用中有不少地方是使用卡片来展示信息,背后应该就是这个CardView. 使用CardView要引入单独的support包:co ...

  4. 自动更新补丁Security Update for Internet Explorer 10 for Windows Server 2008 R2 x64 Edition (KB2964358)失败

    下载http://www.microsoft.com/zh-CN/download/details.aspx?id=42581手动安装成功.

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

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

  6. 以rem为单位根据移动设备的分辨率动态设置font-size

    无需指定font-size的大小 <script> // //- 设置根元素fontSize~ // (function (doc, win) { // var _root = doc.d ...

  7. string模块

    string模块 string模块包括了一些字符串常量, 并且有str对象的功能,主要用来生成一些字符串.字符串格式化等 参考: http://python.usyiyi.cn/python_278/ ...

  8. vmware在桥接模式下配置centos7网络,并使用xshell连接虚拟主机(总结篇)

    虚拟机系统:centos7 mini版本 1.虚拟安装成功之后,首先我配置的是桥接模式,因为我使用的是网线,配置完桥接模式之后我的linux虚拟机就可以访问网络了 2.因为我安装的是centos7的迷 ...

  9. C#大文件读取和查询--内存映射

    笔者最近需要快速查询日志文件,文件大小在4G以上. 需求如下: 1.读取4G左右大小的文件中的指定行,程序运行占用内存不超过500M. 2.希望查询1G以内容,能控制在20s左右. 刚开始觉得这个应该 ...

  10. 转载:谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词

    转载: 谈谈Unicode编码,简要解释UCS.UTF.BMP.BOM等名词 这是一篇程序员写给程序员的趣味读物.所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级 ...