UNPKG

contra-ngx-img-cropper

Version:
1,061 lines 49 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { Bounds } from './model/bounds'; import { CornerMarker } from './model/cornerMarker'; import { CropTouch } from './model/cropTouch'; import { DragMarker } from './model/dragMarker'; import { ImageCropperModel } from './model/imageCropperModel'; import { ImageCropperDataShare } from './imageCropperDataShare'; import { PointPool } from './model/pointPool'; var ImageCropper = (function (_super) { __extends(ImageCropper, _super); function ImageCropper(cropperSettings) { var _this = _super.call(this) || this; var x = 0; var y = 0; var width = cropperSettings.width; var height = cropperSettings.height; var keepAspect = cropperSettings.keepAspect; var touchRadius = cropperSettings.touchRadius; var minWidth = cropperSettings.minWidth; var minHeight = cropperSettings.minHeight; var croppedWidth = cropperSettings.croppedWidth; var croppedHeight = cropperSettings.croppedHeight; _this.cropperSettings = cropperSettings; _this.crop = _this; _this.x = x; _this.y = y; if (width === void 0) { _this.width = 100; } if (height === void 0) { _this.height = 50; } if (keepAspect === void 0) { _this.keepAspect = true; } if (touchRadius === void 0) { _this.touchRadius = 20; } _this.minWidth = minWidth; _this.minHeight = minHeight; _this.keepAspect = false; _this.aspectRatio = 0; _this.currentDragTouches = []; _this.isMouseDown = false; _this.ratioW = 1; _this.ratioH = 1; _this.fileType = cropperSettings.fileType; _this.imageSet = false; _this.pointPool = new PointPool(200); _this.tl = new CornerMarker(x, y, touchRadius, _this.cropperSettings); _this.tr = new CornerMarker(x + width, y, touchRadius, _this.cropperSettings); _this.bl = new CornerMarker(x, y + height, touchRadius, _this.cropperSettings); _this.br = new CornerMarker(x + width, y + height, touchRadius, _this.cropperSettings); _this.tl.addHorizontalNeighbour(_this.tr); _this.tl.addVerticalNeighbour(_this.bl); _this.tr.addHorizontalNeighbour(_this.tl); _this.tr.addVerticalNeighbour(_this.br); _this.bl.addHorizontalNeighbour(_this.br); _this.bl.addVerticalNeighbour(_this.tl); _this.br.addHorizontalNeighbour(_this.bl); _this.br.addVerticalNeighbour(_this.tr); _this.markers = [_this.tl, _this.tr, _this.bl, _this.br]; _this.center = new DragMarker(x + (width / 2), y + (height / 2), touchRadius, _this.cropperSettings); _this.keepAspect = keepAspect; _this.aspectRatio = height / width; _this.croppedImage = new Image(); _this.currentlyInteracting = false; _this.cropWidth = croppedWidth; _this.cropHeight = croppedHeight; return _this; } ImageCropper.sign = function (x) { if (+x === x) { return (x === 0) ? x : (x > 0) ? 1 : -1; } return NaN; }; ImageCropper.getMousePos = function (canvas, evt) { var rect = canvas.getBoundingClientRect(); return PointPool.instance.borrow(evt.clientX - rect.left, evt.clientY - rect.top); }; ImageCropper.getTouchPos = function (canvas, touch) { var rect = canvas.getBoundingClientRect(); return PointPool.instance.borrow(touch.clientX - rect.left, touch.clientY - rect.top); }; ImageCropper.detectVerticalSquash = function (img) { var ih = img.height; var canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = ih; var ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); var imageData = ctx.getImageData(0, 0, 1, ih); if (imageData) { var data = imageData.data; // search image edge pixel position in case it is squashed vertically. var sy = 0; var ey = ih; var py = ih; while (py > sy) { var alpha = data[(py - 1) * 4 + 3]; if (alpha === 0) { ey = py; } else { sy = py; } py = (ey + sy) >> 1; } var ratio = (py / ih); return (ratio === 0) ? 1 : ratio; } else { return 1; } }; ImageCropper.prototype.getDataUriMimeType = function (dataUri) { // Get a substring because the regex does not perform well on very large strings. Cater for optional charset. Length 50 shoould be enough. var dataUriSubstring = dataUri.substring(0, 50); var mimeType = 'image/png'; // data-uri scheme // data:[<media type>][;charset=<character set>][;base64],<data> var regEx = RegExp(/^(data:)([\w\/\+]+);(charset=[\w-]+|base64).*,(.*)/gi); var matches = regEx.exec(dataUriSubstring); if (matches && matches[2]) { mimeType = matches[2]; if (mimeType == 'image/jpg') { mimeType = 'image/jpeg'; } } return mimeType; }; ImageCropper.prototype.prepare = function (canvas) { this.buffer = document.createElement('canvas'); this.cropCanvas = document.createElement('canvas'); // todo get more reliable parent width value. var responsiveWidth = canvas.parentElement ? canvas.parentElement.clientWidth : 0; if (responsiveWidth > 0 && this.cropperSettings.dynamicSizing) { this.cropCanvas.width = responsiveWidth; this.buffer.width = responsiveWidth; canvas.width = responsiveWidth; } else { this.cropCanvas.width = this.cropWidth; this.buffer.width = canvas.width; } this.cropCanvas.height = this.cropHeight; this.buffer.height = canvas.height; this.canvas = canvas; this.ctx = this.canvas.getContext('2d'); this.draw(this.ctx); }; ImageCropper.prototype.resizeCanvas = function (width, height, setImage) { if (setImage === void 0) { setImage = false; } this.canvas.width = this.cropCanvas.width = this.width = this.canvasWidth = this.buffer.width = width; this.canvas.height = this.cropCanvas.height = this.height = this.canvasHeight = this.buffer.height = height; if (setImage) { this.setImage(this.srcImage); } }; ImageCropper.prototype.reset = function () { this.setImage(undefined); }; ImageCropper.prototype.draw = function (ctx) { var bounds = this.getBounds(); if (this.srcImage) { ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); var sourceAspect = this.srcImage.height / this.srcImage.width; var canvasAspect = this.canvasHeight / this.canvasWidth; var w = this.canvasWidth; var h = this.canvasHeight; if (canvasAspect > sourceAspect) { w = this.canvasWidth; h = this.canvasWidth * sourceAspect; } else { h = this.canvasHeight; w = this.canvasHeight / sourceAspect; } this.ratioW = w / this.srcImage.width; this.ratioH = h / this.srcImage.height; if (canvasAspect < sourceAspect) { this.drawImageIOSFix(ctx, this.srcImage, 0, 0, this.srcImage.width, this.srcImage.height, this.buffer.width / 2 - w / 2, 0, w, h); } else { this.drawImageIOSFix(ctx, this.srcImage, 0, 0, this.srcImage.width, this.srcImage.height, 0, this.buffer.height / 2 - h / 2, w, h); } this.buffer.getContext('2d') .drawImage(this.canvas, 0, 0, this.canvasWidth, this.canvasHeight); ctx.lineWidth = this.cropperSettings.cropperDrawSettings.strokeWidth; ctx.strokeStyle = this.cropperSettings.cropperDrawSettings.strokeColor; // 'rgba(255,228,0,1)'; if (!this.cropperSettings.rounded) { ctx.fillStyle = 'rgba(0, 0, 0, 0.6)'; ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); ctx.drawImage(this.buffer, bounds.left, bounds.top, Math.max(bounds.width, 1), Math.max(bounds.height, 1), bounds.left, bounds.top, bounds.width, bounds.height); ctx.strokeRect(bounds.left, bounds.top, bounds.width, bounds.height); } else { ctx.beginPath(); ctx.arc(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2, bounds.width / 2, 0, Math.PI * 2, true); ctx.closePath(); ctx.stroke(); } var marker = void 0; for (var i = 0; i < this.markers.length; i++) { marker = this.markers[i]; marker.draw(ctx); } this.center.draw(ctx); } else { ctx.fillStyle = 'rgba(192,192,192,1)'; ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } }; ImageCropper.prototype.dragCenter = function (x, y, marker) { var bounds = this.getBounds(); var left = x - (bounds.width / 2); var right = x + (bounds.width / 2); var top = y - (bounds.height / 2); var bottom = y + (bounds.height / 2); if (right >= this.maxXClamp) { x = this.maxXClamp - bounds.width / 2; } if (left <= this.minXClamp) { x = bounds.width / 2 + this.minXClamp; } if (top < this.minYClamp) { y = bounds.height / 2 + this.minYClamp; } if (bottom >= this.maxYClamp) { y = this.maxYClamp - bounds.height / 2; } this.tl.moveX(x - (bounds.width / 2)); this.tl.moveY(y - (bounds.height / 2)); this.tr.moveX(x + (bounds.width / 2)); this.tr.moveY(y - (bounds.height / 2)); this.bl.moveX(x - (bounds.width / 2)); this.bl.moveY(y + (bounds.height / 2)); this.br.moveX(x + (bounds.width / 2)); this.br.moveY(y + (bounds.height / 2)); marker.setPosition(x, y); }; ImageCropper.prototype.enforceMinSize = function (x, y, marker) { var xLength = x - marker.getHorizontalNeighbour().position.x; var yLength = y - marker.getVerticalNeighbour().position.y; var xOver = this.minWidth - Math.abs(xLength); var yOver = this.minHeight - Math.abs(yLength); if (xLength === 0 || yLength === 0) { x = marker.position.x; y = marker.position.y; return PointPool.instance.borrow(x, y); } if (this.keepAspect) { if (xOver > 0 && (yOver / this.aspectRatio) > 0) { if (xOver > (yOver / this.aspectRatio)) { if (xLength < 0) { x -= xOver; if (yLength < 0) { y -= xOver * this.aspectRatio; } else { y += xOver * this.aspectRatio; } } else { x += xOver; if (yLength < 0) { y -= xOver * this.aspectRatio; } else { y += xOver * this.aspectRatio; } } } else { if (yLength < 0) { y -= yOver; if (xLength < 0) { x -= yOver / this.aspectRatio; } else { x += yOver / this.aspectRatio; } } else { y += yOver; if (xLength < 0) { x -= yOver / this.aspectRatio; } else { x += yOver / this.aspectRatio; } } } } else { if (xOver > 0) { if (xLength < 0) { x -= xOver; if (yLength < 0) { y -= xOver * this.aspectRatio; } else { y += xOver * this.aspectRatio; } } else { x += xOver; if (yLength < 0) { y -= xOver * this.aspectRatio; } else { y += xOver * this.aspectRatio; } } } else { if (yOver > 0) { if (yLength < 0) { y -= yOver; if (xLength < 0) { x -= yOver / this.aspectRatio; } else { x += yOver / this.aspectRatio; } } else { y += yOver; if (xLength < 0) { x -= yOver / this.aspectRatio; } else { x += yOver / this.aspectRatio; } } } } } } else { if (xOver > 0) { if (xLength < 0) { x -= xOver; } else { x += xOver; } } if (yOver > 0) { if (yLength < 0) { y -= yOver; } else { y += yOver; } } } if (x < this.minXClamp || x > this.maxXClamp || y < this.minYClamp || y > this.maxYClamp) { x = marker.position.x; y = marker.position.y; } return PointPool.instance.borrow(x, y); }; ImageCropper.prototype.dragCorner = function (x, y, marker) { var iX = 0; var iY = 0; var ax = 0; var ay = 0; var newHeight = 0; var newWidth = 0; var newY = 0; var newX = 0; var anchorMarker; var fold = 0; if (this.keepAspect) { anchorMarker = marker.getHorizontalNeighbour().getVerticalNeighbour(); ax = anchorMarker.position.x; ay = anchorMarker.position.y; if (x <= anchorMarker.position.x) { if (y <= anchorMarker.position.y) { iX = ax - (100 / this.aspectRatio); iY = ay - (100 / this.aspectRatio * this.aspectRatio); fold = this.getSide(PointPool.instance.borrow(iX, iY), anchorMarker.position, PointPool.instance.borrow(x, y)); if (fold > 0) { newHeight = Math.abs(anchorMarker.position.y - y); newWidth = newHeight / this.aspectRatio; newY = anchorMarker.position.y - newHeight; newX = anchorMarker.position.x - newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } else { if (fold < 0) { newWidth = Math.abs(anchorMarker.position.x - x); newHeight = newWidth * this.aspectRatio; newY = anchorMarker.position.y - newHeight; newX = anchorMarker.position.x - newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } } } else { iX = ax - (100 / this.aspectRatio); iY = ay + (100 / this.aspectRatio * this.aspectRatio); fold = this.getSide(PointPool.instance.borrow(iX, iY), anchorMarker.position, PointPool.instance.borrow(x, y)); if (fold > 0) { newWidth = Math.abs(anchorMarker.position.x - x); newHeight = newWidth * this.aspectRatio; newY = anchorMarker.position.y + newHeight; newX = anchorMarker.position.x - newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } else { if (fold < 0) { newHeight = Math.abs(anchorMarker.position.y - y); newWidth = newHeight / this.aspectRatio; newY = anchorMarker.position.y + newHeight; newX = anchorMarker.position.x - newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } } } } else { if (y <= anchorMarker.position.y) { iX = ax + (100 / this.aspectRatio); iY = ay - (100 / this.aspectRatio * this.aspectRatio); fold = this.getSide(PointPool.instance.borrow(iX, iY), anchorMarker.position, PointPool.instance.borrow(x, y)); if (fold < 0) { newHeight = Math.abs(anchorMarker.position.y - y); newWidth = newHeight / this.aspectRatio; newY = anchorMarker.position.y - newHeight; newX = anchorMarker.position.x + newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } else { if (fold > 0) { newWidth = Math.abs(anchorMarker.position.x - x); newHeight = newWidth * this.aspectRatio; newY = anchorMarker.position.y - newHeight; newX = anchorMarker.position.x + newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } } } else { iX = ax + (100 / this.aspectRatio); iY = ay + (100 / this.aspectRatio * this.aspectRatio); fold = this.getSide(PointPool.instance.borrow(iX, iY), anchorMarker.position, PointPool.instance.borrow(x, y)); if (fold < 0) { newWidth = Math.abs(anchorMarker.position.x - x); newHeight = newWidth * this.aspectRatio; newY = anchorMarker.position.y + newHeight; newX = anchorMarker.position.x + newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } else { if (fold > 0) { newHeight = Math.abs(anchorMarker.position.y - y); newWidth = newHeight / this.aspectRatio; newY = anchorMarker.position.y + newHeight; newX = anchorMarker.position.x + newWidth; var min = this.enforceMinSize(newX, newY, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } } } } } else { var min = this.enforceMinSize(x, y, marker); marker.move(min.x, min.y); PointPool.instance.returnPoint(min); } this.center.recalculatePosition(this.getBounds()); }; ImageCropper.prototype.getSide = function (a, b, c) { var n = ImageCropper.sign((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)); // TODO move the return of the pools to outside of this function PointPool.instance.returnPoint(a); PointPool.instance.returnPoint(c); return n; }; ImageCropper.prototype.handleRelease = function (newCropTouch) { if (newCropTouch == null) { return; } var index = 0; for (var k = 0; k < this.currentDragTouches.length; k++) { if (newCropTouch.id === this.currentDragTouches[k].id) { this.currentDragTouches[k].dragHandle.setDrag(false); index = k; } } this.currentDragTouches.splice(index, 1); this.draw(this.ctx); }; ImageCropper.prototype.handleMove = function (newCropTouch) { var matched = false; for (var k = 0; k < this.currentDragTouches.length; k++) { if (newCropTouch.id === this.currentDragTouches[k].id && this.currentDragTouches[k].dragHandle != null) { var dragTouch = this.currentDragTouches[k]; var clampedPositions = this.clampPosition(newCropTouch.x - dragTouch.dragHandle.offset.x, newCropTouch.y - dragTouch.dragHandle.offset.y); newCropTouch.x = clampedPositions.x; newCropTouch.y = clampedPositions.y; PointPool.instance.returnPoint(clampedPositions); if (dragTouch.dragHandle instanceof CornerMarker) { this.dragCorner(newCropTouch.x, newCropTouch.y, dragTouch.dragHandle); } else { this.dragCenter(newCropTouch.x, newCropTouch.y, dragTouch.dragHandle); } this.currentlyInteracting = true; matched = true; ImageCropperDataShare.setPressed(this.canvas); break; } } if (!matched) { for (var i = 0; i < this.markers.length; i++) { var marker = this.markers[i]; if (marker.touchInBounds(newCropTouch.x, newCropTouch.y)) { newCropTouch.dragHandle = marker; this.currentDragTouches.push(newCropTouch); marker.setDrag(true); newCropTouch.dragHandle.offset.x = newCropTouch.x - newCropTouch.dragHandle.position.x; newCropTouch.dragHandle.offset.y = newCropTouch.y - newCropTouch.dragHandle.position.y; this.dragCorner(newCropTouch.x - newCropTouch.dragHandle.offset.x, newCropTouch.y - newCropTouch.dragHandle.offset.y, newCropTouch.dragHandle); break; } } if (newCropTouch.dragHandle === null || typeof newCropTouch.dragHandle === 'undefined') { if (this.center.touchInBounds(newCropTouch.x, newCropTouch.y)) { newCropTouch.dragHandle = this.center; this.currentDragTouches.push(newCropTouch); newCropTouch.dragHandle.setDrag(true); newCropTouch.dragHandle.offset.x = newCropTouch.x - newCropTouch.dragHandle.position.x; newCropTouch.dragHandle.offset.y = newCropTouch.y - newCropTouch.dragHandle.position.y; this.dragCenter(newCropTouch.x - newCropTouch.dragHandle.offset.x, newCropTouch.y - newCropTouch.dragHandle.offset.y, newCropTouch.dragHandle); } } } }; ImageCropper.prototype.updateClampBounds = function () { var sourceAspect = this.srcImage.height / this.srcImage.width; var canvasAspect = this.canvas.height / this.canvas.width; var w = this.canvas.width; var h = this.canvas.height; if (canvasAspect > sourceAspect) { w = this.canvas.width; h = this.canvas.width * sourceAspect; } else { h = this.canvas.height; w = this.canvas.height / sourceAspect; } this.minXClamp = this.canvas.width / 2 - w / 2; this.minYClamp = this.canvas.height / 2 - h / 2; this.maxXClamp = this.canvas.width / 2 + w / 2; this.maxYClamp = this.canvas.height / 2 + h / 2; }; ImageCropper.prototype.getCropBounds = function () { var bounds = this.getBounds(); bounds.top = Math.round((bounds.top - this.minYClamp) / this.ratioH); bounds.bottom = Math.round((bounds.bottom - this.minYClamp) / this.ratioH); bounds.left = Math.round((bounds.left - this.minXClamp) / this.ratioW); bounds.right = Math.round((bounds.right - this.minXClamp) / this.ratioW); return bounds; }; ImageCropper.prototype.clampPosition = function (x, y) { if (x < this.minXClamp) { x = this.minXClamp; } if (x > this.maxXClamp) { x = this.maxXClamp; } if (y < this.minYClamp) { y = this.minYClamp; } if (y > this.maxYClamp) { y = this.maxYClamp; } return PointPool.instance.borrow(x, y); }; ImageCropper.prototype.isImageSet = function () { return this.imageSet; }; ImageCropper.prototype.setImage = function (img) { this.srcImage = img; if (!img) { this.imageSet = false; this.draw(this.ctx); } else { this.imageSet = true; this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); var bufferContext = this.buffer.getContext('2d'); bufferContext.clearRect(0, 0, this.buffer.width, this.buffer.height); if (!this.cropperSettings.fileType) this.fileType = this.getDataUriMimeType(img.src); if (this.cropperSettings.minWithRelativeToResolution) { this.minWidth = (this.canvas.width * this.cropperSettings.minWidth / this.srcImage.width); this.minHeight = (this.canvas.height * this.cropperSettings.minHeight / this.srcImage.height); } this.updateClampBounds(); this.canvasWidth = this.canvas.width; this.canvasHeight = this.canvas.height; var cropPosition = this.getCropPositionFromMarkers(); this.setCropPosition(cropPosition); } }; ImageCropper.prototype.updateCropPosition = function (cropBounds) { var cropPosition = this.getCropPositionFromBounds(cropBounds); this.setCropPosition(cropPosition); }; ImageCropper.prototype.setCropPosition = function (cropPosition) { this.tl.setPosition(cropPosition[0].x, cropPosition[0].y); this.tr.setPosition(cropPosition[1].x, cropPosition[1].y); this.bl.setPosition(cropPosition[2].x, cropPosition[2].y); this.br.setPosition(cropPosition[3].x, cropPosition[3].y); this.center.setPosition(cropPosition[4].x, cropPosition[4].y); for (var _i = 0, cropPosition_1 = cropPosition; _i < cropPosition_1.length; _i++) { var position = cropPosition_1[_i]; PointPool.instance.returnPoint(position); } this.vertSquashRatio = ImageCropper.detectVerticalSquash(this.srcImage); this.draw(this.ctx); this.croppedImage = this.getCroppedImageHelper(false, this.cropWidth, this.cropHeight); }; ImageCropper.prototype.getCropPositionFromMarkers = function () { var w = this.canvas.width; var h = this.canvas.height; var tlPos, trPos, blPos, brPos, center; var sourceAspect = this.srcImage.height / this.srcImage.width; var cropBounds = this.getBounds(); var cropAspect = cropBounds.height / cropBounds.width; var cX = this.canvas.width / 2; var cY = this.canvas.height / 2; if (cropAspect > sourceAspect) { var imageH = Math.min(w * sourceAspect, h); var cropW = imageH / cropAspect; tlPos = PointPool.instance.borrow(cX - cropW / 2, cY + imageH / 2); trPos = PointPool.instance.borrow(cX + cropW / 2, cY + imageH / 2); blPos = PointPool.instance.borrow(cX - cropW / 2, cY - imageH / 2); brPos = PointPool.instance.borrow(cX + cropW / 2, cY - imageH / 2); } else { var imageW = Math.min(h / sourceAspect, w); var cropH = imageW * cropAspect; tlPos = PointPool.instance.borrow(cX - imageW / 2, cY + cropH / 2); trPos = PointPool.instance.borrow(cX + imageW / 2, cY + cropH / 2); blPos = PointPool.instance.borrow(cX - imageW / 2, cY - cropH / 2); brPos = PointPool.instance.borrow(cX + imageW / 2, cY - cropH / 2); } center = PointPool.instance.borrow(cX, cY); var positions = [tlPos, trPos, blPos, brPos, center]; return positions; }; ImageCropper.prototype.getCropPositionFromBounds = function (cropPosition) { var marginTop = 0; var marginLeft = 0; var canvasAspect = this.canvasHeight / this.canvasWidth; var sourceAspect = this.srcImage.height / this.srcImage.width; if (canvasAspect > sourceAspect) { marginTop = this.buffer.height / 2 - (this.canvasWidth * sourceAspect) / 2; } else { marginLeft = this.buffer.width / 2 - (this.canvasHeight / sourceAspect) / 2; } var ratioW = (this.canvasWidth - marginLeft * 2) / this.srcImage.width; var ratioH = (this.canvasHeight - marginTop * 2) / this.srcImage.height; var actualH = cropPosition.height * ratioH; var actualW = cropPosition.width * ratioW; var actualX = cropPosition.left * ratioW + marginLeft; var actualY = cropPosition.top * ratioH + marginTop; if (this.keepAspect) { var scaledW = actualH / this.aspectRatio; var scaledH = actualW * this.aspectRatio; if (this.getCropBounds().height === cropPosition.height) { actualH = scaledH; } else if (this.getCropBounds().width === cropPosition.width) { actualW = scaledW; } else { if (Math.abs(scaledH - actualH) < Math.abs(scaledW - actualW)) { actualW = scaledW; } else { actualH = scaledH; } } } var tlPos = PointPool.instance.borrow(actualX, actualY + actualH); var trPos = PointPool.instance.borrow(actualX + actualW, actualY + actualH); var blPos = PointPool.instance.borrow(actualX, actualY); var brPos = PointPool.instance.borrow(actualX + actualW, actualY); var center = PointPool.instance.borrow(actualX + actualW / 2, actualY + actualH / 2); var positions = [tlPos, trPos, blPos, brPos, center]; return positions; }; ImageCropper.prototype.getCroppedImageHelper = function (preserveSize, fillWidth, fillHeight) { if (this.cropperSettings.cropOnResize) { return this.getCroppedImage(preserveSize, fillWidth, fillHeight); } return this.croppedImage ? this.croppedImage : document.createElement('img'); }; // todo: Unused parameters? ImageCropper.prototype.getCroppedImage = function (preserveSize, fillWidth, fillHeight) { var bounds = this.getBounds(); if (!this.srcImage) { return document.createElement('img'); } else { var sourceAspect = this.srcImage.height / this.srcImage.width; var canvasAspect = this.canvas.height / this.canvas.width; var w = this.canvas.width; var h = this.canvas.height; if (canvasAspect > sourceAspect) { w = this.canvas.width; h = this.canvas.width * sourceAspect; } else { if (canvasAspect < sourceAspect) { h = this.canvas.height; w = this.canvas.height / sourceAspect; } else { h = this.canvas.height; w = this.canvas.width; } } this.ratioW = w / this.srcImage.width; this.ratioH = h / this.srcImage.height; var offsetH = (this.buffer.height - h) / 2 / this.ratioH; var offsetW = (this.buffer.width - w) / 2 / this.ratioW; var ctx = this.cropCanvas.getContext('2d'); if (this.cropperSettings.preserveSize || preserveSize) { var width = Math.round(bounds.right / this.ratioW - bounds.left / this.ratioW); var height = Math.round(bounds.bottom / this.ratioH - bounds.top / this.ratioH); this.cropCanvas.width = width; this.cropCanvas.height = height; this.cropperSettings.croppedWidth = this.cropCanvas.width; this.cropperSettings.croppedHeight = this.cropCanvas.height; } else { this.cropCanvas.width = this.cropWidth; this.cropCanvas.height = this.cropHeight; } ctx.clearRect(0, 0, this.cropCanvas.width, this.cropCanvas.height); this.drawImageIOSFix(ctx, this.srcImage, Math.max(Math.round((bounds.left) / this.ratioW - offsetW), 0), Math.max(Math.round(bounds.top / this.ratioH - offsetH), 0), Math.max(Math.round(bounds.width / this.ratioW), 1), Math.max(Math.round(bounds.height / this.ratioH), 1), 0, 0, this.cropCanvas.width, this.cropCanvas.height); if (this.cropperSettings.resampleFn) { this.cropperSettings.resampleFn(this.cropCanvas); } this.croppedImage.width = this.cropCanvas.width; this.croppedImage.height = this.cropCanvas.height; this.croppedImage.src = this.cropCanvas.toDataURL(this.fileType, this.cropperSettings.compressRatio); return this.croppedImage; } }; ImageCropper.prototype.getBounds = function () { var minX = Number.MAX_VALUE; var minY = Number.MAX_VALUE; var maxX = -Number.MAX_VALUE; var maxY = -Number.MAX_VALUE; for (var i = 0; i < this.markers.length; i++) { var marker = this.markers[i]; if (marker.position.x < minX) { minX = marker.position.x; } if (marker.position.x > maxX) { maxX = marker.position.x; } if (marker.position.y < minY) { minY = marker.position.y; } if (marker.position.y > maxY) { maxY = marker.position.y; } } var bounds = new Bounds(); bounds.left = minX; bounds.right = maxX; bounds.top = minY; bounds.bottom = maxY; return bounds; }; ImageCropper.prototype.setBounds = function (bounds) { var topLeft; var topRight; var bottomLeft; var bottomRight; var currentBounds = this.getBounds(); for (var i = 0; i < this.markers.length; i++) { var marker = this.markers[i]; if (marker.position.x === currentBounds.left) { if (marker.position.y === currentBounds.top) { marker.setPosition(bounds.left, bounds.top); } else { marker.setPosition(bounds.left, bounds.bottom); } } else { if (marker.position.y === currentBounds.top) { marker.setPosition(bounds.right, bounds.top); } else { marker.setPosition(bounds.right, bounds.bottom); } } } this.center.recalculatePosition(bounds); this.center.draw(this.ctx); this.draw(this.ctx); // we need to redraw all canvas if we have changed bounds }; ImageCropper.prototype.onTouchMove = function (event) { if (this.crop.isImageSet()) { event.preventDefault(); if (event.touches.length === 1) { for (var i = 0; i < event.touches.length; i++) { var touch = event.touches[i]; var touchPosition = ImageCropper.getTouchPos(this.canvas, touch); var cropTouch = new CropTouch(touchPosition.x, touchPosition.y, touch.identifier); PointPool.instance.returnPoint(touchPosition); this.move(cropTouch); } } else { if (event.touches.length === 2) { var distance = ((event.touches[0].clientX - event.touches[1].clientX) * (event.touches[0].clientX - event.touches[1].clientX)) + ((event.touches[0].clientY - event.touches[1].clientY) * (event.touches[0].clientY - event.touches[1].clientY)); if (this.previousDistance && this.previousDistance !== distance) { var bounds = this.getBounds(); if (distance < this.previousDistance) { bounds.top += 1; bounds.left += 1; bounds.right -= 1; bounds.bottom -= 1; } if (distance > this.previousDistance) { if (bounds.top !== this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left !== this.minXClamp && bounds.right !== this.maxXClamp) { bounds.top -= 1; bounds.left -= 1; bounds.right += 1; bounds.bottom += 1; } else if (bounds.top !== this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left === this.minXClamp && bounds.right !== this.maxXClamp) { bounds.top -= 1; bounds.right += 2; bounds.bottom += 1; } else if (bounds.top !== this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left !== this.minXClamp && bounds.right === this.maxXClamp) { bounds.top -= 1; bounds.left -= 2; bounds.bottom += 1; } else if (bounds.top === this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left !== this.minXClamp && bounds.right !== this.maxXClamp) { bounds.left -= 1; bounds.right += 1; bounds.bottom += 2; } else if (bounds.top !== this.minYClamp && bounds.bottom === this.maxYClamp && bounds.left !== this.minXClamp && bounds.right !== this.maxXClamp) { bounds.top -= 2; bounds.left -= 1; bounds.right += 1; } else if (bounds.top === this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left === this.minXClamp && bounds.right !== this.maxXClamp) { bounds.right += 2; bounds.bottom += 2; } else if (bounds.top === this.minYClamp && bounds.bottom !== this.maxYClamp && bounds.left !== this.minXClamp && bounds.right === this.maxXClamp) { bounds.left -= 2; bounds.bottom += 2; } else if (bounds.top !== this.minYClamp && bounds.bottom === this.maxYClamp && bounds.left === this.minXClamp && bounds.right !== this.maxXClamp) { bounds.top -= 2; bounds.right += 2; } else if (bounds.top !== this.minYClamp && bounds.bottom === this.maxYClamp && bounds.left !== this.minXClamp && bounds.right === this.maxXClamp) { bounds.top -= 2; bounds.left -= 2; } } if (bounds.top < this.minYClamp) bounds.top = this.minYClamp; if (bounds.bottom > this.maxYClamp) bounds.bottom = this.maxYClamp; if (bounds.left < this.minXClamp) bounds.left = this.minXClamp; if (bounds.right > this.maxXClamp) bounds.right = this.maxXClamp; this.setBounds(bounds); } this.previousDistance = distance; } } this.draw(this.ctx); } }; ImageCropper.prototype.onMouseMove = function (e) { if (this.crop.isImageSet() && this.isMouseDown) { var mousePosition = ImageCropper.getMousePos(this.canvas, e); this.move(new CropTouch(mousePosition.x, mousePosition.y, 0)); var dragTouch = this.getDragTouchForID(0); if (dragTouch) { dragTouch.x = mousePosition.x; dragTouch.y = mousePosition.y; } else { dragTouch = new CropTouch(mousePosition.x, mousePosition.y, 0); } PointPool.instance.returnPoint(mousePosition); this.drawCursors(dragTouch); this.draw(this.ctx); } }; ImageCropper.prototype.move = function (cropTouch) { if (this.isMouseDown) { this.handleMove(cropTouch); } }; ImageCropper.prototype.getDragTouchForID = function (id) { for (var i = 0; i < this.currentDragTouches.length; i++) { if (id === this.currentDragTouches[i].id) { return this.currentDragTouches[i]; } } return undefined; }; ImageCropper.prototype.drawCursors = function (cropTouch) { var cursorDrawn = false; if (cropTouch != null) { if (cropTouch.dragHandle === this.center) { ImageCropperDataShare.setStyle(this.canvas, 'move'); cursorDrawn = true; } if (cropTouch.dragHandle !== null && cropTouch.dragHandle instanceof CornerMarker) { this.drawCornerCursor(cropTouch.dragHandle, cropTouch.dragHandle.position.x, cropTouch.dragHandle.position.y); cursorDrawn = true; } } var didDraw = false; if (!cursorDrawn) { for (var i = 0; i < this.markers.length; i++) { didDraw = didDraw || this.drawCornerCursor(this.markers[i], cropTouch.x, cropTouch.y); } if (!didDraw) { ImageCropperDataShare.setStyle(this.canvas, 'initial'); } } if (!didDraw && !cursorDrawn && this.center.touchInBounds(cropTouch.x, cropTouch.y)) { this.center.setOver(true); ImageCropperDataShare.setOver(this.canvas); ImageCropperDataShare.setStyle(this.canvas, 'move'); } else { this.center.setOver(false); } }; ImageCropper.prototype.drawCornerCursor = function (marker, x, y) { if (marker.touchInBounds(x, y)) { marker.setOver(true); if (marker.getHorizontalNeighbour().position.x > marker.position.x) { if (marker.getVerticalNeighbour().position.y > marker.position.y) { ImageCropperDataShare.setOver(this.canvas); ImageCropperDataShare.setStyle(this.canvas, 'nwse-resize'); } else { ImageCropperDataShare.setOver(this.canvas); ImageCropperDataShare.setStyle(this.canvas, 'nesw-resize'); } } else { if (marker.getVerticalNeighbour().position.y > marker.position.y) { ImageCropperDataShare.setOver(this.canvas); ImageCropperDataShare.setStyle(this.canvas, 'nesw-resize'); } else { ImageCropperDataShare.setOver(this.canvas); ImageCropperDataShare.setStyle(this.canvas, 'nwse-resize'); } } return true; } marker.setOver(false); return false; }; // todo: Unused param ImageCropper.prototype.onTouchStart = function (event) { if (this.crop.isImageSet()) { this.isMouseDown = true; } }; ImageCropper.prototype.onTouchEnd = function (event) { if (this.crop.isImageSet()) { for (var i = 0; i < event.changedTouches.length; i++) { var touch = event.changedTouches[i]; var dragTouch = this.getDragTouchForID(touch.identifier); if (dragTouch && dragTouch !== undefined) { if (dragTouch.dragHandle instanceof CornerMarker || dragTouch.dragHandle instanceof DragMarker) { dragTouch.dragHandle.setOver(false); } this.handleRelease(dragTouch); } } if (this.currentDragTouches.length === 0) { this.isMouseDown = false; this.currentlyInteracting = false; } } }; // http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios ImageCropper.prototype.drawImageIOSFix = function (ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { // Works only if whole image is displayed: // ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); // The following works correct also when only a part of the image is displayed: // ctx.drawImage(img, sx * this.vertSquashRatio, sy * this.vertSquashRatio, sw * this.vertSquashRatio, sh * // this.vertSquashRatio, dx, dy, dw, dh); ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); }; ImageCropper.prototype.onMouseDown = function (event) { if (this.crop.isImageSet()) { this.isMouseDown = true; } }; ImageCropper.prototype.onMouseUp = function (event) { if (this.crop.isImageSet()) { ImageCropperDataShare.setReleased(this.canvas); this.isMouseDown = false; this.handleRelease(new CropTouch(0, 0, 0)); } }; return ImageCropper; }(ImageCropperModel)); export { ImageCropper }; //# sourceMappingURL=imageCropper.js.map