Skip to content

Commit d4348f2

Browse files
committed
add new crop style
1 parent 3a10380 commit d4348f2

File tree

7 files changed

+171
-111
lines changed

7 files changed

+171
-111
lines changed

site/client/components/doc/en/CropImage.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<vue-core-image-upload
1515
crop-ratio="1:1"
1616
class="btn btn-primary"
17-
resize="local"
17+
crop="local"
1818
url="http://101.198.151.190/api/upload.php"
1919
extensions="png,jpeg,jpg"
2020
text="Crop Image"

site/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"j-i-c": "^2.0.2",
2525
"promise-polyfill": "^6.0.2",
2626
"vue": "^2.3.2",
27-
"vue-core-image-upload": "^2.1.9",
27+
"vue-core-image-upload": "^2.1.11",
2828
"vue-highlight": "0.0.0",
2929
"vue-highlightjs": "^1.2.2",
3030
"vue-progressbar": "^0.7.1",

src/crop.vue

Lines changed: 148 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,62 @@
11
<template>
2-
<div class="g-crop-image-principal">
3-
<div class="image-wrap" :style="{ width:width + 'px',height: height + 'px' }">
4-
<img ref="crop-image" :src="src" :style="{ width:'100%',height: '100%', }">
5-
</div>
6-
<div class="image-mask" v-if="!hideCrop">
7-
<div class="mask top" :style="{ top:0, height: cropCSS.top + 'px', left: 0, width: '100%'}"></div>
8-
<div class="mask bottom" :style="{ bottom:0, top: (cropCSS.top + cropCSS.height) + 'px', left: 0, width: '100%'}"></div>
9-
<div class="mask left" :style="{top: cropCSS.top + 'px', height: cropCSS.height + 'px', left:0, width: cropCSS.left + 'px'}"></div>
10-
<div class="mask right" :style="{top: cropCSS.top + 'px', height: cropCSS.height + 'px', left: (cropCSS.left + cropCSS.width) + 'px', right: 0}"></div>
11-
</div>
12-
<div class="crop-box" v-if="!hideCrop" v-on:touchstart.self="drag" v-on:mousedown.self="drag" :style="{top: cropCSS.top + 'px', left: cropCSS.left + 'px', height: cropCSS.height + 'px', width: cropCSS.width + 'px'}">
13-
<div class="reference-line v"></div>
14-
<div class="reference-line h"></div>
15-
<a class="g-resize" v-on:touchstart.self="resize" v-on:mousedown.self="resize"></a>
2+
<div class="image-aside">
3+
<div class="g-crop-image-box" >
4+
<div class="g-crop-image-principal" v-on:touchstart.capture="drag" v-on:mousedown.capture="drag">
5+
<div class="image-wrap" :style="{ width: width + 'px',height: height + 'px', left: left+ 'px', top: top + 'px', backgroundImage: 'url(' + src + ')', cursor: isResize ? 'default' : 'move'}">
6+
<img ref="crop-image" style="width:0;height:0;" :src="src" />
7+
</div>
8+
<div class="image-mask" v-if="!isResize">
9+
<div class="mask top" :style="{ top:0, height: cropCSS.top + 'px', left: 0, width: '100%'}"></div>
10+
<div class="mask bottom" :style="{ bottom:0, top: (cropCSS.top + cropCSS.height) + 'px', left: 0, width: '100%'}"></div>
11+
<div class="mask left" :style="{top: cropCSS.top + 'px', height: cropCSS.height + 'px', left:0, width: cropCSS.left + 'px'}"></div>
12+
<div class="mask right" :style="{top: cropCSS.top + 'px', height: cropCSS.height + 'px', left: (cropCSS.left + cropCSS.width) + 'px', right: 0}"></div>
13+
</div>
14+
<div class="crop-box" v-if="!isResize" :style="{top: cropCSS.top + 'px', left: cropCSS.left + 'px', height: cropCSS.height + 'px', width: cropCSS.width + 'px'}">
15+
<div class="reference-line v"></div>
16+
<div class="reference-line h"></div>
17+
<a class="g-resize" v-on:touchstart.self="resize" v-on:mousedown.self="resize"></a>
18+
</div>
19+
20+
</div>
21+
<resize-bar v-if="resize" ref="resizeBar" @resize="resizeImage"></resize-bar>
1622
</div>
1723
</div>
1824
</template>
1925

2026
<style scoped>
27+
.g-crop-image-principal{
28+
overflow: hidden;
29+
background-color: #fff;
30+
background-image: -webkit-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef),-webkit-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef);
31+
background-image: -moz-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef),-moz-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef);
32+
background-image: -o-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef),-o-linear-gradient(bottom left, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef);
33+
background-image: linear-gradient(to top right, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef),linear-gradient(to top right, #efefef 25%, transparent 25%, transparent 75%, #efefef 75%, #efefef);
34+
background-position: 0 0,10px 10px;
35+
-webkit-background-size: 21px 21px;
36+
background-size: 21px 21px;
37+
}
38+
.image-aside{
39+
overflow: hidden;
40+
position: absolute;
41+
right: 30px;
42+
left:30px;
43+
top:70px;
44+
bottom:40px;
45+
text-align: center;
46+
}
47+
.image-aside .image-wrap{
48+
position: absolute;
49+
left: 0;
50+
top: 0;
51+
-webkit-touch-callout: none;
52+
-webkit-user-select: none;
53+
-khtml-user-select: none;
54+
-moz-user-select: none;
55+
-ms-user-select: none;
56+
user-select: none;
57+
box-shadow: 0 3px 5px -2px rgba(0,0,0,.25);
58+
background-size: cover;
59+
}
2160
.image-mask{
2261
position: absolute;
2362
left: 0;
@@ -30,6 +69,7 @@
3069
background-color: rgba(255,255,255,.6);
3170
}
3271
.crop-box{
72+
z-index: 2000;
3373
box-sizing: border-box;
3474
position: absolute;
3575
background: none;
@@ -90,14 +130,17 @@ import drag from './lib/drag';
90130
import resize from './lib/resize';
91131
import GIF_LOADING_SRC from './lib/loading-gif';
92132
import helper from './lib/helper';
133+
import ResizeBar from './resize-bar.vue';
93134
// set cropbox size in image
94135
const CROPBOX_PERCENT = 75;
136+
const isMobile = helper.isMobile;
137+
const areaWidth = window.innerWidth - 60;
138+
const areaHeight = window.innerHeight - 110;
95139
export default {
140+
components: {
141+
ResizeBar,
142+
},
96143
props: {
97-
formId: {
98-
type: String,
99-
default: '',
100-
},
101144
ratio: {
102145
type: String,
103146
default: '1:1'
@@ -110,8 +153,8 @@ export default {
110153
type: Number,
111154
default: 50,
112155
},
113-
hideCrop: {
114-
type: [String, Boolean],
156+
isResize: {
157+
type: [Boolean],
115158
default: false,
116159
}
117160
},
@@ -121,6 +164,10 @@ export default {
121164
src: GIF_LOADING_SRC,
122165
width: 24,
123166
height: 24,
167+
initWidth: 24,
168+
initHeight: 24,
169+
left: 0,
170+
top: 0,
124171
cropCSS: {
125172
126173
}
@@ -139,71 +186,103 @@ export default {
139186
this.ratioH = 1;
140187
this.ratioVal = this.ratio;
141188
}
142-
this.setLayout(w, h);
143-
this.setCropBox();
144189
this.natrualWidth = w;
145190
this.natrualHeight = h;
191+
this.setLayout(w, h);
192+
const resizeBar = this.$refs.resizeBar;
193+
if (this.isResize) {
194+
resizeBar.setProgress(100);
195+
} else {
196+
resizeBar.setProgress(0);
197+
}
146198
return this.imgChangeRatio;
147199
},
148-
149200
resizeImage(progress) {
150-
const w = this.natrualWidth * this.imgChangeRatio * progress;
151-
const h = this.natrualHeight * this.imgChangeRatio * progress;
201+
let w,
202+
h;
203+
if (this.isResize) {
204+
w = this.natrualWidth * this.imgChangeRatio * progress;
205+
h = this.natrualHeight * this.imgChangeRatio * progress;
206+
} else {
207+
w = this.initWidth + progress * (this.natrualWidth - this.initWidth);
208+
h = this.initHeight + progress * (this.natrualHeight - this.initHeight);
209+
}
152210
if (w <= this.minWidth || h < this.minHeight) {
153211
return;
154212
}
155-
this._setStyle(w, h, w/h);
156-
this.setCropBox();
213+
this.left += (this.width - w) / 2;
214+
this.top += (this.height - h) / 2;
215+
this.width = w;
216+
this.height = h;
217+
this.imgChangeRatio = this.width / this.natrualWidth;
157218
},
158219
159220
setLayout(w, h) {
160-
let H = window.innerHeight - 80,
161-
W = window.innerWidth - 60,
221+
let H = areaHeight,
222+
W = areaWidth,
162223
width = w,
163224
height = h,
164-
marginLeft = 0;
225+
marginLeft = 0,
226+
marginTop = 0;
165227
166228
// caculate the image ratio
167229
let R = width / height;
168230
let Rs = W / H;
169231
if (R > Rs) {
170-
width = W;
171-
height = W / R;
172-
marginLeft = (H - W / R) / 2;
232+
height = H;
233+
width = H * R;
234+
marginLeft = (W - H * R) / 2;
173235
} else {
174236
width = H * R,
175237
height = H;
176238
marginLeft = (W - H * R) / 2;
177239
}
178-
this.marginLeft = marginLeft;
179-
this.marginTop = 0;
180-
this.imgChangeRatio = width / w;
181-
this._setStyle(width, height, R, true);
240+
this._setStyle(width, height, marginLeft, marginTop, R, true);
182241
},
183242
184-
_setStyle(w, h, r, isInit) {
185-
const $container = this.$el;
243+
_setStyle(w, h, ml, mt, r, isInit) {
244+
const $container = this.$el.querySelector('.g-crop-image-principal');
186245
if(!isInit) {
187246
this.marginLeft = this.marginLeft + (this.width - w) / 2;
188247
this.marginTop = this.marginTop + (this.height - h) / 2;
189248
}
190249
$container.style.cssText = 'width:' + w + 'px;height:' + h + 'px;margin-left:'
191-
+ this.marginLeft + 'px;' + 'margin-top:' + this.marginTop + 'px';
192-
this.width = w;
193-
this.height = h;
250+
+ ml + 'px;' + 'margin-top:' + mt + 'px';
251+
this.setCropBox(w, h);
252+
if (this.isResize) {
253+
this.width = w;
254+
this.height = h;
255+
} else {
256+
if (r >= 1) {
257+
this.height = this.cropCSS.height;
258+
this.width = this.height * r;
259+
} else {
260+
this.width = this.cropCSS.width;
261+
this.height = this.width / r;
262+
}
263+
this.initWidth = this.width;
264+
this.initHeight = this.height;
265+
this.left = (w - this.width) / 2;
266+
this.top = (h - this.height) / 2;
267+
}
268+
this.imgChangeRatio = this.width / this.natrualWidth;
194269
},
195270
196-
setCropBox() {
197-
if (this.hideCrop) {
271+
setCropBox(w, h, r) {
272+
if (this.isResize) {
198273
return;
199274
}
200275
let $selectCropBox = this.__find('.crop-box');
201276
let $wrap = this.$el;
202-
let imageWidth = this.width,
203-
imageHeight = this.height;
204-
let ratioW = this.ratioW,
277+
let imageWidth = w,
278+
imageHeight = h,
279+
ratioW = this.ratioW,
205280
ratioH = this.ratioH;
206-
const baseCropWidth = (imageWidth / 100) * CROPBOX_PERCENT;
281+
let cropWidth = imageWidth;
282+
if (areaWidth < w) {
283+
cropWidth = areaWidth;
284+
}
285+
const baseCropWidth = (cropWidth / 100) * CROPBOX_PERCENT;
207286
const CSSObj = {
208287
width: baseCropWidth,
209288
height: (baseCropWidth / ratioW) * ratioH,
@@ -220,11 +299,12 @@ export default {
220299
$selectCropBox.style.cssText = helper.setCssText(CSSObj);
221300
};
222301
this.cropCSS = CSSObj;
302+
223303
},
224304
225305
getCropData() {
226306
// keep compatible with old api
227-
if (this.hideCrop) {
307+
if (this.isResize) {
228308
return {
229309
imgChangeRatio: this.imgChangeRatio,
230310
toCropImgX: 0,
@@ -234,8 +314,8 @@ export default {
234314
};
235315
}
236316
return {
237-
toCropImgX: this.cropCSS.left / this.imgChangeRatio,
238-
toCropImgY: this.cropCSS.top / this.imgChangeRatio,
317+
toCropImgX: (this.cropCSS.left - this.left) / this.imgChangeRatio,
318+
toCropImgY: (this.cropCSS.top - this.top) / this.imgChangeRatio,
239319
toCropImgW: this.cropCSS.width / this.imgChangeRatio,
240320
toCropImgH: this.cropCSS.height / this.imgChangeRatio,
241321
};
@@ -246,12 +326,15 @@ export default {
246326
},
247327
248328
__find(str) {
249-
let dq = document.querySelector('#vciu-modal-' + this.formId);
329+
let dq = this.$el;
250330
return dq.querySelector(str);
251331
},
252332
// resize and drag move
253333
resize(e) {
254334
e.stopPropagation();
335+
if (!this.ratio.indexOf(':')) {
336+
return;
337+
}
255338
let $el = e.target.parentElement;
256339
let $container = this.__find('.g-crop-image-principal');
257340
if (this._$container) {
@@ -261,8 +344,8 @@ export default {
261344
const coor = {
262345
x: helper.isMobile ? e.touches[0].clientX : e.clientX,
263346
y: helper.isMobile ? e.touches[0].clientY : e.clientY,
264-
w: parseInt(window.getComputedStyle($el).width, 10),
265-
h: parseInt(window.getComputedStyle($el).height, 10)
347+
w: $el.offsetWidth,
348+
h: $el.offsetHeight,
266349
};
267350
this.el = $el;
268351
this.container = $container;
@@ -283,7 +366,6 @@ export default {
283366
document.removeEventListener('mousemove', move, false);
284367
document.removeEventListener('mouseup', end, false);
285368
};
286-
287369
if (helper.isMobile) {
288370
document.addEventListener('touchmove', move, false);
289371
document.addEventListener('touchend', end, false);
@@ -294,25 +376,25 @@ export default {
294376
295377
drag(e) {
296378
e.preventDefault();
297-
const $el = e.target;
379+
const $el = this.__find('.image-wrap');
298380
this.el = $el;
299-
const $container = this.$el;
300-
const $infoAside = document.getElementsByClassName('image-aside')[0];
381+
const $cropBox = this.__find('.crop-box');
382+
const $container = e.currentTarget;
301383
const self = this;
302384
const isMobile = helper.isMobile;
303385
const coor = {
304-
x: (isMobile ? e.touches[0]['clientX'] : e.clientX) - $el.offsetLeft - $el.parentElement.offsetLeft - $infoAside.offsetLeft,
305-
y: (isMobile ? e.touches[0]['clientY'] : e.clientY) - $el.offsetTop - $el.parentElement.offsetTop - $infoAside.offsetTop,
306-
posX: isMobile ? e.touches[0]['clientX'] : e.clientX,
307-
posy: isMobile ? e.touches[0]['clientY'] : e.clientY,
308-
maxLeft: parseInt($container.style.width) - parseInt($el.style.width),
309-
maxTop: parseInt($container.style.height) - parseInt($el.style.height),
386+
x: (isMobile ? e.touches[0]['clientX'] : e.clientX) - $el.offsetLeft,
387+
y: (isMobile ? e.touches[0]['clientY'] : e.clientY) - $el.offsetTop,
388+
maxLeft: $cropBox.offsetLeft,
389+
maxTop: $cropBox.offsetTop,
390+
minLeft: ($cropBox.offsetWidth + $cropBox.offsetLeft) - $el.offsetWidth,
391+
minTop: ($cropBox.offsetHeight + $cropBox.offsetTop) - $el.offsetHeight,
310392
};
311393
const move = function (ev) {
312394
const newCropStyle = drag(ev, self.el, coor);
313395
if (newCropStyle) {
314-
self.cropCSS.left = newCropStyle.left;
315-
self.cropCSS.top = newCropStyle.top;
396+
self.left = newCropStyle.left;
397+
self.top = newCropStyle.top;
316398
}
317399
};
318400
const stopMove = function (ev) {

0 commit comments

Comments
 (0)