Skip to content

Commit 9fcffcc

Browse files
committed
[FEAT] : 다운로드 기능 추가
closed #3
1 parent a9e763a commit 9fcffcc

File tree

8 files changed

+77
-30
lines changed

8 files changed

+77
-30
lines changed

src/components/common/FileUploader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const FileUploader = () => {
4343
};
4444

4545
return (
46-
<Label htmlFor="file" aria-label="이미지 업로드">
46+
<Label htmlFor="file" aria-label="업로드">
4747
<FileInput type="file" id="file" name="file" onChange={handelFile} ref={fileRef} />
4848
<SVG
4949
width="15"

src/components/common/Select.js

-2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ const Select = ({ data, onChange }) => {
1818
selectRef.current.size = 5;
1919
};
2020
const handleBlur = () => {
21-
console.log('blur');
2221
selectRef.current.size = 1;
2322
};
2423
const handleChange = () => {
25-
//resetSize();
2624
selectRef.current.blur();
2725
};
2826
useEffect(() => {

src/components/container/ImagesContainer.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ const ImagesContainer = () => {
8585
[selectedList, dispatch],
8686
);
8787

88+
const onReset = () => setSelectedList([]);
89+
8890
const onDelete = () => {
8991
dispatch(deletePicture(selectedList));
9092
dispatch(clearSelectedPictures());
@@ -97,6 +99,22 @@ const ImagesContainer = () => {
9799
setSelectedList([]);
98100
};
99101

102+
const onDownload = () => {
103+
if (!selectedList.length) {
104+
alert('⚠ 이미지를 선택해주세요 ⚠');
105+
return;
106+
}
107+
if (selectedList.length > 1) {
108+
alert('⚠ 한번에 하나의 이미지만 다운로드할 수 있습니다 ⚠');
109+
return;
110+
}
111+
112+
const link = document.createElement('a');
113+
link.href = pictures.find(p => p.id === selectedList[0]).src;
114+
link.download = 'awesome pictor.jpg';
115+
link.click();
116+
};
117+
100118
const onCrop = () => {
101119
if (selectedList.length > 1) {
102120
alert('⚠ 한번에 하나의 이미지만 크롭할 수 있습니다 ⚠');
@@ -111,7 +129,10 @@ const ImagesContainer = () => {
111129
<TopButtons>
112130
<ButtonInner>
113131
<FileUploader />
114-
<Button padding="5px" margin="0 5px 0 0" onClick={onDelete} aria-label="이미지 삭제">
132+
<Button padding="5px" margin="0 5px 0 0" onClick={onDownload} aria-label="다운로드">
133+
<SVG width="15" height="15" path="M16 11h5l-9 10-9-10h5v-11h8v11zm1 11h-10v2h10v-2z" />
134+
</Button>
135+
<Button padding="5px" margin="0 5px 0 0" onClick={onDelete} aria-label="삭제">
115136
<SVG
116137
width="15"
117138
height="15"
@@ -120,7 +141,14 @@ const ImagesContainer = () => {
120141
</Button>
121142
</ButtonInner>
122143
<ButtonInner>
123-
<Button padding="5px" margin="0 5px 0 0" onClick={onCrop} aria-label="이미지 자르기">
144+
<Button padding="5px" margin="0 5px 0 0" onClick={onReset} aria-label="선택 초기화">
145+
<SVG
146+
width="15"
147+
height="15"
148+
path="M18.885 3.515c-4.617-4.618-12.056-4.676-16.756-.195l-2.129-2.258v7.938h7.484l-2.066-2.191c2.82-2.706 7.297-2.676 10.073.1 4.341 4.341 1.737 12.291-5.491 12.291v4.8c3.708 0 6.614-1.244 8.885-3.515 4.686-4.686 4.686-12.284 0-16.97z"
149+
/>
150+
</Button>
151+
<Button padding="5px" margin="0 5px 0 0" onClick={onCrop} aria-label="자르기">
124152
<SVG
125153
width="15"
126154
height="15"

src/components/container/PatternsContainer.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ const SettingsContainer = () => {
5252

5353
return (
5454
<>
55-
<TopButtons>
55+
<TopButtons flex="flex-end">
5656
<Button padding="5px" margin="0 5px 0 0" onClick={onReset} aria-label="설정 초기화">
5757
<SVG
5858
width="15"
5959
height="15"
60-
path="M2.458 9.012c-.297.947-.458 1.955-.458 3 0 5.52 4.481 10 10 10 5.52 0 10-4.48 10-10 0-5.519-4.48-10-10-10-2.121 0-4.083.668-5.703 1.796l1.703 2.204h-6.58l1.935-6.012 1.718 2.223c1.958-1.389 4.346-2.211 6.927-2.211 6.623 0 12 5.377 12 12s-5.377 11.988-12 11.988-12-5.365-12-11.988c0-1.036.132-2.041.379-3h2.079zm10.35-3.012c.292.821.375 1.346 1.01 1.609.637.264 1.073-.052 1.854-.423l1.142 1.142c-.373.787-.687 1.218-.423 1.854.262.634.784.716 1.609 1.009v1.617c-.816.29-1.347.375-1.61 1.01-.264.636.052 1.071.424 1.853l-1.142 1.142c-.79-.375-1.219-.687-1.85-.424-.639.265-.723.793-1.014 1.611h-1.616c-.292-.821-.375-1.347-1.01-1.61-.637-.264-1.072.052-1.854.423l-1.142-1.142c.366-.771.689-1.212.423-1.854-.263-.635-.793-.719-1.609-1.009v-1.617c.817-.29 1.346-.373 1.609-1.009.264-.637-.051-1.07-.423-1.854l1.142-1.142c.788.374 1.218.687 1.854.423.635-.263.719-.792 1.01-1.609h1.616zm-.808 8c-1.105 0-2-.896-2-2 0-1.105.895-2.001 2-2.001 1.104 0 2 .896 2 2.001 0 1.104-.896 2-2 2z"
60+
path="M18.885 3.515c-4.617-4.618-12.056-4.676-16.756-.195l-2.129-2.258v7.938h7.484l-2.066-2.191c2.82-2.706 7.297-2.676 10.073.1 4.341 4.341 1.737 12.291-5.491 12.291v4.8c3.708 0 6.614-1.244 8.885-3.515 4.686-4.686 4.686-12.284 0-16.97z"
6161
/>
6262
</Button>
6363
</TopButtons>

src/components/layout/tabPanel/TopButtons.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import styled from 'styled-components';
33

44
const Wrapper = styled.div`
55
display: flex;
6-
justify-content: space-between;
6+
justify-content: ${props => (props.flex ? props.flex : 'space-between')};
77
align-items: center;
88
padding: 5px;
99
border-bottom: 2px solid var(--border-light-gray);
1010
`;
1111

12-
const TopButtons = ({ children }) => {
12+
const TopButtons = ({ flex, children }) => {
1313
//console.log('TopButtons');
14-
return <Wrapper>{children}</Wrapper>;
14+
return <Wrapper flex={flex}>{children}</Wrapper>;
1515
};
1616

1717
export default TopButtons;

src/components/parts/Canvas.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const Canvas = ({ setMyCanvas }) => {
2929

3030
// 캔버스 사이즈 변경
3131
const handleResize = () => {
32-
console.log('handleResize', wrapperRef.current.offsetWidth);
3332
setCanvasSize({
3433
width: wrapperRef.current.offsetWidth,
3534
height: wrapperRef.current.offsetHeight - 1,
@@ -69,12 +68,12 @@ const Canvas = ({ setMyCanvas }) => {
6968
// myCanvas 생성
7069
const cropImgSrc = drawnPicture ? pictures.find(pic => pic.id === drawnPicture).src : null;
7170
my.current = new MyCanvas(wrapperRef.current, canvasRef.current, ctx.current, cropImgSrc);
72-
my.current.initCropImage(); // 이미지 초기화
71+
my.current.initImage(); // 이미지 초기화
7372
setMyCanvas(my.current);
7473

7574
switch (canvasMode) {
7675
case 'crop':
77-
console.log('crop!!!!');
76+
//console.log('crop!!!!');
7877
my.current.drawnImg.onload = function () {
7978
my.current.drawImage(1.0);
8079
};
@@ -84,11 +83,11 @@ const Canvas = ({ setMyCanvas }) => {
8483
my.current.canvas.addEventListener('mousedown', mousedownRef.current);
8584
break;
8685
case 'pattern':
87-
console.log('pattern!!!!');
86+
//console.log('pattern!!!!');
8887
my.current.makePattern(properties);
8988
break;
9089
case 'clear':
91-
console.log('clear!!!!');
90+
//console.log('clear!!!!');
9291
// clear canvas
9392
my.current.clear();
9493
break;

src/lib/myCanvas.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ MyCanvas.prototype.clear = function () {
4545
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
4646
};
4747

48-
// 크롭할 이미지 로드하기
49-
MyCanvas.prototype.initCropImage = function () {
50-
//console.log('initCropImage', this.drawnImgSrc.substr(20, 30));
48+
// 이미지 로드하기
49+
MyCanvas.prototype.initImage = function () {
50+
//console.log('initImage', this.drawnImgSrc.substr(20, 30));
5151
this.clear();
5252
this.drawnImg = new Image();
5353
this.drawnImg.src = this.drawnImgSrc;
@@ -169,7 +169,7 @@ MyCanvas.prototype.crop = function () {
169169
);
170170

171171
// 새로운 이미지 생성. 기존 크롭이미지 대체
172-
this.drawnImgSrc = c.toDataURL();
172+
this.drawnImgSrc = c.toDataURL('image/png', 1);
173173
this.isCropped = !this.isCropped;
174174

175175
// 이전 포인트 지우기
@@ -178,7 +178,7 @@ MyCanvas.prototype.crop = function () {
178178

179179
MyCanvas.prototype.makePattern = function (props) {
180180
const myPattern = new MyPattern(this.wrapper, this.canvas, this.ctx, this.drawnImgSrc);
181-
myPattern.initCropImage();
181+
myPattern.initImage();
182182

183183
// 설정값 초기화
184184
myPattern.setColor = props.color;
@@ -189,11 +189,12 @@ MyCanvas.prototype.makePattern = function (props) {
189189
myPattern.setGap = props.gap;
190190
myPattern.setType = props.type;
191191

192-
myPattern.makePattern();
192+
// 이미지 저장 시 myCanvas.drawnImgSrc 참조하므로 getter로 src저장
193+
this.drawnImgSrc = myPattern.getPatternSrc;
193194

194195
// const my = this;
195196
// const img = new Image();
196-
// img.src = c.toDataURL();
197+
// img.src = c.toDataURL('image/jpeg');
197198
// img.onload = function () {
198199
// // 새 이미지 페이지에 삽입하기
199200
// my.wrapper.appendChild(this);

src/lib/myPattern.js

+29-8
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,31 @@ export class MyPattern extends MyCanvas {
3737
this.type = value;
3838
}
3939

40-
drawBackgroundColor() {
41-
this.ctx.beginPath();
42-
this.ctx.fillStyle = this.color;
43-
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
44-
this.ctx.closePath();
40+
// src 리턴
41+
get getPatternSrc() {
42+
this.makePattern();
43+
44+
// 캔버스 생성
45+
const c = document.createElement('canvas');
46+
const cx = c.getContext('2d');
47+
// 패턴 사이즈에 맞추기
48+
c.width = this.canvasWidth;
49+
c.height = this.canvasHeight;
50+
cx.drawImage(
51+
this.canvas,
52+
0,
53+
0,
54+
this.canvasWidth,
55+
this.canvasHeight,
56+
0,
57+
0,
58+
this.canvasWidth,
59+
this.canvasHeight,
60+
);
61+
return c.toDataURL('image/jpeg', 1);
4562
}
4663

4764
makePattern() {
48-
this.clear(); // 캔버스 초기화
49-
5065
this.drawBackgroundColor(); // 배경색 그리기
5166

5267
// 설정한 캔버스 사이즈만큼 context 크기 잘라두고 그 안에서 패턴 뿌림
@@ -79,7 +94,13 @@ export class MyPattern extends MyCanvas {
7994

8095
// 그 뒤 다시 이전 context로 restore
8196
this.ctx.restore();
82-
this.drawnImgSrc = this.canvas.toDataURL();
97+
}
98+
99+
drawBackgroundColor() {
100+
this.ctx.beginPath();
101+
this.ctx.fillStyle = this.color;
102+
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
103+
this.ctx.closePath();
83104
}
84105

85106
getXVanilla(i) {

0 commit comments

Comments
 (0)