8000 . · rurusyu/image-editor-vue@7ab6b0c · GitHub
[go: up one dir, main page]

Skip to content

Commit 7ab6b0c

Browse files
committed
.
1 parent 28e9d72 commit 7ab6b0c

File tree

5 files changed

+181
-15
lines changed

5 files changed

+181
-15
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
"dependencies": {
1212
"core-js": "^3.6.4",
1313
"fabric": "^3.6.3",
14+
"fabric-history": "^1.6.0",
1415
"swiper": "^5.3.6",
1516
"vue": "^2.6.11",
1617
"vue-awesome-swiper": "^4.1.0",
18+
"vue-color": "^2.7.1",
1719
"vue-router": "^3.1.5",
1820
"vuex": "^3.1.2"
1921
},

src/components/Canvas.vue

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,35 @@
77
v-model="fontSize"
88
@change="setFontSize"
99
/>
10-
<canvas ref="can" width="1080" height="1080" class="canvas1" id="canvas" ></canvas>
10+
<canvas ref="can" width="1080" height="300" class="canvas1" id="canvas" ></canvas>
1111
<button @click="saveObjects">Save</button>
12+
<button @click="history('undo')">Undo</button>
13+
<button @click="history('redo')">Redo</button>
14+
<sketch-picker v-if="colorPicker" v-model="colors" @input="setBackgroundColor" />
1215
</div>
1316
</template>
1417

1518
<script>
1619
1720
import { fabric } from 'fabric';
21+
import { Sketch } from 'vue-color';
1822
1923
export default {
2024
name: 'Canvas',
21-
25+
components: {
26+
'sketch-picker': Sketch
27+
},
2228
data(){
2329
return {
2430
canvas:'',
2531
ref:'',
2632
shapeList:[],
2733
fontSize: 20,
34+
backgroundColor: '#ffffff',
35+
colors: {
36+
rgba: { r: 255, g: 255, b: 255, a: 1 },
37+
a: 1
38+
}
2839
}
2940
},
3041
props:{
@@ -39,6 +50,10 @@ export default {
3950
download: {
4051
type: Boolean,
4152
required: true,
53+
},
54+
colorPicker: {
55+
type: Boolean,
56+
required: true,
4257
}
4358
},
4459
watch: {
@@ -92,7 +107,7 @@ export default {
92107
download() {
93108
if(this.$props.download) {
94109
const canvas = document.getElementById('canvas');
95-
const dataURL = canvas.toDataURL('image/png', 1.0);
110+
const dataURL = canvas.toDataURL({ multiplier: 3 });
96111
97112
var link = document.createElement('a');
98113
@@ -106,9 +121,81 @@ export default {
106121
}
107122
}
108123
},
124+
created() {
125+
fabric.Canvas.prototype.historyInit = function () {
126+
this.historyUndo = [];
127+
this.historyRedo = [];
128+
this.historyNextState = this.historyNext();
129+
130+
// vue watch? 혹은 어딘가에서 canvas.on 이벤트 밑에 3개 감시하고 있다가
131+
// 그대로 실행? this.historySaveAction(this.canvas); this를 줘야 undefined 안 나올테니
132+
133+
this.on({
134+
"object:added": this.historySaveAction,
135+
"object:removed": this.historySaveAction,
136+
"object:modified": this.historySaveAction
137+
})
138+
}
139+
140+
fabric.Canvas.prototype.historyNext = function () {
141+
return JSON.stringify(this.toDatalessJSON(this.extraProps));
142+
}
143+
144+
fabric.Canvas.prototype.historySaveAction = function () {
145+
if (this.historyProcessing)
146+
return;
147+
148+
const json = this.historyNextState;
149+
this.historyUndo.push(json);
150+
this.historyNextState = this.historyNext();
151+
}
152+
153+
// 되돌리기
154+
fabric.Canvas.prototype.undo = function (callback) {
155+
this.historyProcessing = true;
156+
157+
const history = this.historyUndo.pop();
158+
if (history) {
159+
// 방금 취소한 행동을 기록하기 위해 배열에 넣음
160+
this.historyRedo.push(this.historyNext());
161+
this.historyNextState = history;
162+
this._loadHistory(history, 'history:undo', callback);
163+
} else {
164+
this.historyProcessing = false;
165+
}
166+
167+
this.historyProcessing = false;
168+
},
169+
170+
// 되돌리기 실행 취소
171+
fabric.Canvas.prototype.redo = function (callback) {
172+
this.historyProcessing = true;
173+
const history = this.historyRedo.pop();
174+
if (history) {
175+
this.historyUndo.push(this.historyNext());
176+
this.historyNextState = history;
177+
this._loadHistory(history, 'history:redo', callback);
178+
} else {
179+
this.historyProcessing = false;
180+
}
181+
},
182+
183+
fabric.Canvas.prototype._loadHistory = function(history, event, callback) {
184+
let _this = this;
185+
186+
this.loadFromJSON(history, function() {
187+
_this.renderAll();
188+
_this.historyProcessing = false;
189+
190+
if (callback && typeof callback === 'function')
191+
callback();
192+
});
193+
}
194+
},
109195
mounted() {
110196
this.ref = this.$refs.can;
111197
this.canvas = new fabric.Canvas(this.ref);
198+
this.canvas.historyInit();
112199
this.data = this.canvas;
113200
114201
let items = window.localStorage.getItem('_tempItems');
@@ -140,22 +227,51 @@ export default {
140227
this.canvas.add(rect);
141228
return rect;
142229
},
230+
addCircle() {
231+
const circle = new fabric.Circle({
232+
left: 150,
233+
top: 150,
234+
radius: 30,
235+
strokeWidth: 1,
236+
stroke: 'black',
237+
fill: 'green',
238+
selectable: true,
239+
originX: 'center', originY: 'center'
240+
})
241+
this.canvas.add(circle);
242+
return circle;
243+
},
143244
addText() {
144245
const text = new fabric.IText('Type some Text', {
145246
fontFamily: 'Arial',
146-
fontSize: 150,
247+
fontSize: 50,
147248
});
148249
149250
this.canvas.add(text);
150251
return text;
151252
},
152253
setFontSize(e) {
153254
const activeObj = this.canvas.getActiveObject();
154-
activeObj.fontSize = e.target.value;
255+
activeObj.setFontSize(e.target.value);
256+
// activeObj.fontSize = e.target.value;
155257
this.fontSize = e.target.value;
156258
157259
this.canvas.renderAll();
158260
},
261+
setBackgroundColor (value) {
262+
console.log('색상', value);
263+
this.canvas.setBackgroundColor(value.hex8, this.canvas.renderAll.bind(this.canvas));
264+
this.canvas.renderAll();
265+
},
266+
history(state) {
267+
console.log('상태 변경', this.canvas.historyUndo);
268+
269+
if(state === 'undo') {
270+
this.canvas.undo()
271+
} else {
272+
this.canvas.redo()
273+
}
274+
},
159275
changeText() {
160276
// message,
161277
// text = new fabric.IText('Type some Text', {

src/components/WrapperCanvas.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="wapper-canvas">
33
<div v-for="(item, index) in NumberOfCanvas" :key="item" @click="selectCanvas(index+1)">
4-
<canvas-view ref="foo" :backgroundImage="backgroundImage" :images="images" :download="download" ></canvas-view>
4+
<canvas-view ref="foo" :backgroundImage="backgroundImage" :colorPicker="colorPicker" :images="images" :download="download" ></canvas-view>
55
</div>
66

77
</div>
@@ -36,6 +36,10 @@ export default {
3636
download: {
3737
type: Boolean,
3838
required: true
39+
},
40+
colorPicker: {
41+
type: Boolean,
42+
required: true
3943
}
4044
},
4145
watch:{
@@ -44,8 +48,8 @@ export default {
4448
switch(this.$props.addShape){
4549
case'rect':
4650
return this.$refs.foo[0].addRect();
47-
case'tri':
48-
return this.$refs.foo[0].addTriAngle();
51+
case'circle':
52+
return this.$refs.foo[0].addCircle();
4953
case'text':
5054
return this.$refs.foo[0].addText();
5155
}

src/views/Home.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
<button type="button" @click="onBackImgDeleted">배경이미지 삭제</button>
1111
</div>
1212
<div class="inputWrapper object">
13-
<button type="button" @click="onObjectCreate">오브젝트 생성</button>
13+
<button type="button" @click="onObjectCreate('rect')">사각형 생성</button>
1414
</div>
15-
<div class="inputWrapper text">
16-
<span>텍스트 작성</span>
17-
<input type="file" class="fileInput" ref="uploadImageFile" @change="onFileSelected" />
15+
<div class="inputWrapper object">
16+
<button type="button" @click="onObjectCreate('circle')">동그라미 생성</button>
17+
</div>
18+
<div class="inputWrapper object">
19+
<button type="button" @click="onObjectCreate('text')">텍스트 생성</button>
1820
</div>
1921
<button @click="exportToPng">다운로드</button>
2022
</div>
@@ -23,6 +25,7 @@
2325
:NumberOfCanvas="NumberOfCanvas"
2426
:addShape="addShape"
2527
:backgroundImage="backgroundImage"
28+
:colorPicker="colorPicker"
2629
:images="images"
2730
:download="download"
2831
/>
@@ -45,6 +48,7 @@ export default {
4548
NumberOfCanvas: 1,
4649
addShape:'',
4750
backgroundImage: {},
51+
colorPicker: true,
4852
images: [],
4953
download: false
5054
}
@@ -61,18 +65,21 @@ export default {
6165
6266
this.backgroundImage = { 'image': URL.createObjectURL(image)};
6367
event.target.value ='';
68+
this.colorPicker = false;
69+
6470
},
6571
onBackImgDeleted() {
6672
this.backgroundImage = {};
73+
this.colorPicker = true;
6774
},
6875
onFileSelected(event) {
6976
const image = event.target.files[0];
7077
7178
this.images.push(URL.createObjectURL(image));
7279
event.target.value ='';
7380
},
74-
onObjectCreate() {
75-
this.addShape = 'text';
81+
onObjectCreate(shape) {
82+
this.addShape = shape;
7683
},
7784
exportToPng() {
7885
this.download = !this.download;

yarn.lock

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
26042604
inherits "^2.0.1"
26052605
safe-buffer "^5.0.1"
26062606

2607+
clamp@^1.0.1:
2608+
version "1.0.1"
2609+
resolved "https://registry.yarnpkg.com/clamp/-/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634"
2610+
integrity sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=
2611+
26072612
class-utils@^0.3.5:
26082613
version "0.3.6"
26092614
resolved "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -4162,7 +4167,14 @@ extsprintf@^1.2.0:
41624167
resolved "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
41634168
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
41644169

4165-
fabric@^3.6.3:
4170+
fabric-history@^1.6.0:
4171+
version "1.6.0"
4172+
resolved "https://registry.yarnpkg.com/fabric-history/-/fabric-history-1.6.0.tgz#edc72397c37027357445fe84ecd03fdc3ff68214"
4173+
integrity sha512-a2njIpTgmtwcFliCRSC9t0uy1sUwSmGShvhxUO5H19uFzLgCuLivlxleXUIYjGC5QQmWQE7ooEa3/KETxtuLhA==
4174+
dependencies:
4175+
fabric "^3.3.2"
4176+
4177+
fabric@^3.3.2, fabric@^3.6.3:
41664178
version "3.6.3"
41674179
resolved "https://registry.yarnpkg.com/fabric/-/fabric-3.6.3.tgz#c72b148911e4d180747f7bb0f12ad158a4508dfc"
41684180
integrity sha512-PwJKZG7Zbst+B1PSmt2OddK8UJ9tQ23a9gslodCSrXCzj8S+1RcOaQuA9gbpoQWpXYUB0qsBhdBvAVyOi7oM9g==
@@ -6356,6 +6368,11 @@ lodash.sortby@^4.7.0:
63566368
resolved "https://registry.npm.taobao.org/lodash.sortby/download/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
63576369
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
63586370

6371+
lodash.throttle@^4.0.0:
6372+
version "4.1.1"
6373+
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
6374+
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
6375+
63596376
lodash.transform@^4.6.0:
63606377
version "4.6.0"
63616378
resolved "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0"
@@ -6469,6 +6486,11 @@ map-visit@^1.0.0:
64696486
dependencies:
64706487
object-visit "^1.0.0"
64716488

6489+
material-colors@^1.0.0:
6490+
version "1.2.6"
6491+
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
6492+
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
6493+
64726494
md5.js@^1.3.4:
64736495
version "1.3.5"
64746496
resolved "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -9626,6 +9648,11 @@ timsort@^0.3.0:
96269648
resolved "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
96279649
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
96289650

9651+
tinycolor2@^1.1.2:
9652+
version "1.4.1"
9653+
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
9654+
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
9655+
96299656
tmp@^0.0.33:
96309657
version "0.0.33"
96319658
resolved "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -10051,6 +10078,16 @@ vue-awesome-swiper@^4.1.0:
1005110078
resolved "https://registry.yarnpkg.com/vue-awesome-swiper/-/vue-awesome-swiper-4.1.0.tgz#163e94597b119e5476d80380e208d2d9a7419c75"
1005210079
integrity sha512-00d6KIRquR+K6Q5dYIJoEdfRSVoE3MTQVilh9x1ZCYXTbChmlaZpwfoyMW2kH7poVq3a5IhBfHf9S9X7KbpITw==
1005310080

10081+
vue-color@^2.7.1:
10082+
version "2.7.1"
10083+
resolved "https://registry.yarnpkg.com/vue-color/-/vue-color-2.7.1.tgz#ca035109ea0010f0d60b889b97d63d37ac712f2d"
10084+
integrity sha512-u3yl46B2eEej9zfAOIRRSphX1QfeNQzMwO82EIA+aoi0AKX3o1KcfsmMzm4BFkkj2ukCxLVfQ41k7g1gSI7SlA==
10085+
dependencies:
10086+
clamp "^1.0.1"
10087+
lodash.throttle "^4.0.0"
10088+
material-colors "^1.0.0"
10089+
tinycolor2 "^1.1.2"
10090+
1005410091
vue-eslint-parser@^7.0.0:
1005510092
version "7.0.0"
1005610093
resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.0.0.tgz#a4ed2669f87179dedd06afdd8736acbb3a3864d6"

0 commit comments

Comments
 (0)
0