contra-ngx-img-cropper
Version:
contra image cropper utility
1,061 lines • 49 kB
JavaScript
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