Skip to content

Commit

Permalink
Changed rendering mechanism, markup structure, and class names
Browse files Browse the repository at this point in the history
Breaking change: .cropit-image-preview is now .cropit-preview.

.cropit-image-preview-container is no longer needed even for image
background.

New markup:

```
.cropit-preview
  .cropit-preview-background-container
    img.cropit-preview-background
  .cropit-preview-image-container
    img.cropit-preview-image
```

Only .cropit-preview is required when initiating the pluging. All other
elements are generated within cropit.

Now preview image is rendered as a `<img>` tag, and both preview image
and background image are moved around using CSS transform.

Improved performance using `will-change`.
  • Loading branch information
Scott Cheng committed Feb 27, 2016
1 parent f6eb24f commit b1f1d01
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 337 deletions.
9 changes: 2 additions & 7 deletions demo/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<script src="../dist/jquery.cropit.js"></script>

<style>
.cropit-image-preview {
.cropit-preview {
background-color: #f8f8f8;
background-size: cover;
border: 1px solid #ccc;
Expand All @@ -17,11 +17,6 @@
cursor: move;
}

.cropit-image-background {
opacity: .2;
cursor: auto;
}

.image-size-label {
margin-top: 10px;
}
Expand All @@ -38,7 +33,7 @@
<body>
<div class="image-editor">
<input type="file" class="cropit-image-input">
<div class="cropit-image-preview"></div>
<div class="cropit-preview"></div>
<div class="image-size-label">
Resize image
</div>
Expand Down
9 changes: 2 additions & 7 deletions demo/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<script src="../dist/jquery.cropit.js"></script>

<style>
.cropit-image-preview {
.cropit-preview {
background-color: #f8f8f8;
background-size: cover;
border: 1px solid #ccc;
Expand All @@ -17,11 +17,6 @@
cursor: move;
}

.cropit-image-background {
opacity: .2;
cursor: auto;
}

.image-size-label {
margin-top: 10px;
}
Expand Down Expand Up @@ -52,7 +47,7 @@
<form action="#">
<div class="image-editor">
<input type="file" class="cropit-image-input">
<div class="cropit-image-preview"></div>
<div class="cropit-preview"></div>
<div class="image-size-label">
Resize image
</div>
Expand Down
9 changes: 3 additions & 6 deletions demo/image-background.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<script src="../dist/jquery.cropit.js"></script>

<style>
.cropit-image-preview {
.cropit-preview {
background-color: #f8f8f8;
background-size: cover;
border: 5px solid #ccc;
Expand All @@ -17,7 +17,7 @@
cursor: move;
}

.cropit-image-background {
.cropit-preview-background {
opacity: .2;
cursor: auto;
}
Expand All @@ -41,10 +41,7 @@
<body>
<div class="image-editor">
<input type="file" class="cropit-image-input">
<!-- .cropit-image-preview-container is needed for background image to work -->
<div class="cropit-image-preview-container">
<div class="cropit-image-preview"></div>
</div>
<div class="cropit-preview"></div>
<div class="image-size-label">
Resize image
</div>
Expand Down
125 changes: 64 additions & 61 deletions dist/jquery.cropit.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ return /******/ (function(modules) { // webpackBootstrap
},

prop: function prop(name, value) {
var capitalizedName = (0, _utils.capitalize)(name);
if ((0, _utils.exists)(value)) {
return applyOnEach(this, function (cropit) {
cropit[name] = value;
Expand Down Expand Up @@ -210,45 +209,64 @@ return /******/ (function(modules) { // webpackBootstrap
_this.onImageError.call(_this, _constants.ERRORS.IMAGE_FAILED_TO_LOAD);
};

this.$preview = this.options.$preview.css('position', 'relative');
this.$fileInput = this.options.$fileInput.attr({ accept: 'image/*' });
this.$preview = this.options.$preview.css({ backgroundRepeat: 'no-repeat' });
this.$zoomSlider = this.options.$zoomSlider.attr({ min: 0, max: 1, step: 0.01 });

this.previewSize = {
width: this.options.width || this.$preview.width(),
height: this.options.height || this.$preview.height()
};

this.$image = (0, _jquery2['default'])('<img />').addClass(_constants.CLASS_NAMES.PREVIEW_IMAGE).attr('alt', '').css({
transformOrigin: 'top left',
webkitTransformOrigin: 'top left',
willChange: 'transform'
});
var $imageContainer = (0, _jquery2['default'])('<div />').addClass(_constants.CLASS_NAMES.PREVIEW_IMAGE_CONTAINER).css({
position: 'absolute',
overflow: 'hidden',
left: 0,
top: 0,
width: '100%',
height: '100%'
}).append(this.$image);
this.$preview.append($imageContainer);

if (this.options.imageBackground) {
if (_jquery2['default'].isArray(this.options.imageBackgroundBorderWidth)) {
this.imageBgBorderWidthArray = this.options.imageBackgroundBorderWidth;
this.bgBorderWidthArray = this.options.imageBackgroundBorderWidth;
} else {
this.imageBgBorderWidthArray = [];
[0, 1, 2, 3].forEach(function (i) {
_this.imageBgBorderWidthArray[i] = _this.options.imageBackgroundBorderWidth;
this.bgBorderWidthArray = [0, 1, 2, 3].map(function () {
return _this.options.imageBackgroundBorderWidth;
});
}

var $previewContainer = this.options.$previewContainer;
this.$imageBg = (0, _jquery2['default'])('<img />').addClass(_constants.CLASS_NAMES.IMAGE_BACKGROUND).attr('alt', '').css('position', 'absolute');
this.$imageBgContainer = (0, _jquery2['default'])('<div />').addClass(_constants.CLASS_NAMES.IMAGE_BACKGROUND_CONTAINER).css({
this.$bg = (0, _jquery2['default'])('<img />').addClass(_constants.CLASS_NAMES.PREVIEW_BACKGROUND).attr('alt', '').css({
position: 'relative',
left: this.bgBorderWidthArray[3],
top: this.bgBorderWidthArray[0],
transformOrigin: 'top left',
webkitTransformOrigin: 'top left',
willChange: 'transform'
});
this.$bgContainer = (0, _jquery2['default'])('<div />').addClass(_constants.CLASS_NAMES.PREVIEW_BACKGROUND_CONTAINER).css({
position: 'absolute',
zIndex: 0,
left: -this.imageBgBorderWidthArray[3] + window.parseInt(this.$preview.css('border-left-width') || 0),
top: -this.imageBgBorderWidthArray[0] + window.parseInt(this.$preview.css('border-top-width') || 0),
width: this.previewSize.width + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
height: this.previewSize.height + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
}).append(this.$imageBg);
if (this.imageBgBorderWidthArray[0] > 0) {
this.$imageBgContainer.css('overflow', 'hidden');
top: -this.bgBorderWidthArray[0],
right: -this.bgBorderWidthArray[1],
bottom: -this.bgBorderWidthArray[2],
left: -this.bgBorderWidthArray[3]
}).append(this.$bg);
if (this.bgBorderWidthArray[0] > 0) {
this.$bgContainer.css('overflow', 'hidden');
}
$previewContainer.css('position', 'relative').prepend(this.$imageBgContainer);
this.$preview.css('position', 'relative');
this.$preview.prepend(this.$bgContainer);

this.$preview.hover(function () {
_this.$imageBg.addClass(_constants.CLASS_NAMES.PREVIEW_HOVERED);
_this.$bg.addClass(_constants.CLASS_NAMES.PREVIEW_HOVERED);
}, function () {
_this.$imageBg.removeClass(_constants.CLASS_NAMES.PREVIEW_HOVERED);
_this.$bg.removeClass(_constants.CLASS_NAMES.PREVIEW_HOVERED);
});
}

Expand Down Expand Up @@ -406,9 +424,9 @@ return /******/ (function(modules) { // webpackBootstrap

this.options.imageState = {};

this.$preview.css('background-image', 'url(' + this.image.src + ')');
this.$image.attr('src', this.image.src);
if (this.options.imageBackground) {
this.$imageBg.attr('src', this.image.src);
this.$bg.attr('src', this.image.src);
}

this.setImageLoadedClass();
Expand Down Expand Up @@ -581,6 +599,22 @@ return /******/ (function(modules) { // webpackBootstrap
value: function isZoomable() {
return this.zoomer.isZoomable();
}
}, {
key: 'renderImage',
value: function renderImage() {
var transformation = 'translate(' + this.offset.x + 'px, ' + this.offset.y + 'px) scale(' + this.zoom + ')';

this.$image.css({
transform: transformation,
webkitTransform: transformation
});
if (this.options.imageBackground) {
this.$bg.css({
transform: transformation,
webkitTransform: transformation
});
}
}
}, {
key: 'getCroppedImageData',
value: function getCroppedImageData(exportOptions) {
Expand Down Expand Up @@ -648,13 +682,7 @@ return /******/ (function(modules) { // webpackBootstrap
}

this._offset = this.fixOffset(position);
this.$preview.css('background-position', '' + this.offset.x + 'px ' + this.offset.y + 'px');
if (this.options.imageBackground) {
this.$imageBg.css({
left: this.offset.x + this.imageBgBorderWidthArray[3],
top: this.offset.y + this.imageBgBorderWidthArray[0]
});
}
this.renderImage();

this.options.onOffsetChange(position);
},
Expand All @@ -666,32 +694,21 @@ return /******/ (function(modules) { // webpackBootstrap
set: function (newZoom) {
newZoom = this.fixZoom(newZoom);

var updatedWidth = (0, _utils.round)(this.image.width * newZoom);
var updatedHeight = (0, _utils.round)(this.image.height * newZoom);

if (this.imageLoaded) {
var oldZoom = this.zoom;

var newX = this.previewSize.width / 2 - (this.previewSize.width / 2 - this.offset.x) * newZoom / oldZoom;
var newY = this.previewSize.height / 2 - (this.previewSize.height / 2 - this.offset.y) * newZoom / oldZoom;

this._zoom = newZoom;
this.offset = { x: newX, y: newY };
this.offset = { x: newX, y: newY }; // Triggers renderImage()
} else {
this._zoom = newZoom;
}

this.zoomSliderPos = this.zoomer.getSliderPos(this.zoom);
this.$zoomSlider.val(this.zoomSliderPos);

this.$preview.css('background-size', '' + updatedWidth + 'px ' + updatedHeight + 'px');
if (this.options.imageBackground) {
this.$imageBg.css({
width: updatedWidth,
height: updatedHeight
});
}

this.options.onZoomChange(newZoom);
},
get: function () {
Expand Down Expand Up @@ -783,13 +800,6 @@ return /******/ (function(modules) { // webpackBootstrap
height: this.previewSize.height
});

if (this.options.imageBackground && this.$imageBgContainer) {
this.$imageBgContainer.css({
width: this.previewSize.width + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
height: this.previewSize.height + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
});
}

if (this.imageLoaded) {
this.setupZoomer();
}
Expand Down Expand Up @@ -901,12 +911,14 @@ return /******/ (function(modules) { // webpackBootstrap

exports.PLUGIN_KEY = PLUGIN_KEY;
var CLASS_NAMES = {
PREVIEW: 'cropit-image-preview',
PREVIEW_CONTAINER: 'cropit-image-preview-container',
PREVIEW: 'cropit-preview',
PREVIEW_IMAGE_CONTAINER: 'cropit-preview-image-container',
PREVIEW_IMAGE: 'cropit-preview-image',
PREVIEW_BACKGROUND_CONTAINER: 'cropit-preview-background-container',
PREVIEW_BACKGROUND: 'cropit-preview-background',
FILE_INPUT: 'cropit-image-input',
ZOOM_SLIDER: 'cropit-image-zoom-input',
IMAGE_BACKGROUND: 'cropit-image-background',
IMAGE_BACKGROUND_CONTAINER: 'cropit-image-background-container',

PREVIEW_HOVERED: 'cropit-preview-hovered',
DRAG_HOVERED: 'cropit-drag-hovered',
IMAGE_LOADING: 'cropit-image-loading',
Expand Down Expand Up @@ -956,10 +968,6 @@ return /******/ (function(modules) { // webpackBootstrap
name: '$zoomSlider',
description: 'Range input element that controls image zoom.',
defaultSelector: 'input.' + _constants.CLASS_NAMES.ZOOM_SLIDER
}, {
name: '$previewContainer',
description: 'Preview container. Only needed when `imageBackground` is true.',
defaultSelector: '.' + _constants.CLASS_NAMES.PREVIEW_CONTAINER
}].map(function (o) {
o.type = 'jQuery element';
o['default'] = '$imageCropper.find(\'' + o.defaultSelector + '\')';
Expand Down Expand Up @@ -1123,12 +1131,7 @@ return /******/ (function(modules) { // webpackBootstrap
var round = function round(x) {
return +(Math.round(x * 100) + 'e-2');
};

exports.round = round;
var capitalize = function capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
};
exports.capitalize = capitalize;

/***/ }
/******/ ])
Expand Down
10 changes: 6 additions & 4 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export const PLUGIN_KEY = 'cropit';

export const CLASS_NAMES = {
PREVIEW: 'cropit-image-preview',
PREVIEW_CONTAINER: 'cropit-image-preview-container',
PREVIEW: 'cropit-preview',
PREVIEW_IMAGE_CONTAINER: 'cropit-preview-image-container',
PREVIEW_IMAGE: 'cropit-preview-image',
PREVIEW_BACKGROUND_CONTAINER: 'cropit-preview-background-container',
PREVIEW_BACKGROUND: 'cropit-preview-background',
FILE_INPUT: 'cropit-image-input',
ZOOM_SLIDER: 'cropit-image-zoom-input',
IMAGE_BACKGROUND: 'cropit-image-background',
IMAGE_BACKGROUND_CONTAINER: 'cropit-image-background-container',

PREVIEW_HOVERED: 'cropit-preview-hovered',
DRAG_HOVERED: 'cropit-drag-hovered',
IMAGE_LOADING: 'cropit-image-loading',
Expand Down
Loading

0 comments on commit b1f1d01

Please sign in to comment.