Skip to content

Commit

Permalink
v2.6.5
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
ssi02014 authored Feb 28, 2023
2 parents 8abe922 + 533bc49 commit 8d30b3b
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 225 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-thumbnail-generator",
"version": "2.6.2",
"version": "2.6.5",
"description": "react-thumbnail-generator",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
291 changes: 156 additions & 135 deletions src/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
@@ -1,145 +1,166 @@
import useDragAndDropText from '../../components/hooks/useDragAndDropText';
import useDragAndDropText from '../../hooks/useDragAndDropText';
import React, { useEffect } from 'react';
import { Color } from 'react-color-palette';
import { CanvasState } from '../../types/canvas';
import { CanvasStateWithColors } from '../../types/canvas';
import * as S from './styled';

interface CanvasProps {
canvasState: CanvasState;
bgColor: Color;
fontColor: Color;
strokeColor: Color;
canvasState: CanvasStateWithColors;
}

const Canvas = React.forwardRef(
({ canvasState, bgColor, fontColor, strokeColor }: CanvasProps, ref: any) => {
const {
value,
canvasWidth,
canvasHeight,
fontSize,
fontStrokeType,
selectedImage,
fontFamily,
angle,
isBlur,
isBlockEvent,
} = canvasState;
const {
dragAndDropTextData,
handleCanvasMouseDown,
handleCanvasMouseMove,
handleCanvasMouseUp,
handleCanvasMouseLeave,
handleCanvasOffsetReset,
} = useDragAndDropText(+canvasWidth, +canvasHeight);

const getLineWidthByStrokeType = () => {
const strokeObj = {
None: 0,
Thin: 3,
Normal: 5,
Thick: 7,
} as { [key: string]: number };

return strokeObj[fontStrokeType];
};

const calculateDirection = (
linesLength: number,
lineHeight: number,
idx: number
) => {
const { offsetX, offsetY } = dragAndDropTextData;

const x = offsetX ? offsetX : +canvasWidth / 2;
const y = offsetY
? offsetY - ((linesLength - 1) * lineHeight) / 2 + idx * lineHeight
: +canvasHeight / 2 -
((linesLength - 1) * lineHeight) / 2 +
idx * lineHeight;

return { x, y };
};

const setCanvasText = (ctx: CanvasRenderingContext2D) => {
const { offsetX, offsetY } = dragAndDropTextData;
const lines = value.split('\n');
const size = +fontSize.replace('px', '');
const lineHeight = size * 1.15;
const centerX = +canvasWidth / 2;
const centerY = +canvasHeight / 2;

ctx.font = `${size}px ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

ctx.save(); // 현재 상태 저장
ctx.translate(offsetX ? offsetX : centerX, offsetY ? offsetY : centerY); // 중심으로 이동
ctx.rotate((+angle * Math.PI) / 180); // 회전
ctx.translate(
offsetX ? -offsetX : -centerX,
offsetY ? -offsetY : -centerY
); // 이전 위치로 이동

lines.forEach((line, idx) => {
const { x, y } = calculateDirection(lines.length, lineHeight, idx);

ctx.save();
ctx.translate(x, y);

if (fontStrokeType !== 'None') {
ctx.lineWidth = getLineWidthByStrokeType();
ctx.strokeStyle = `${strokeColor.hex}`;
ctx.strokeText(line, 0, 0);
}
ctx.fillStyle = fontColor.hex;
ctx.fillText(line, 0, 0);
ctx.restore();
});
const Canvas = React.forwardRef(({ canvasState }: CanvasProps, ref: any) => {
const {
value,
canvasWidth,
canvasHeight,
fontSize,
fontStrokeType,
selectedImage,
fontFamily,
angle,
isBlur,
isBlockEvent,
bgColor,
fontColor,
strokeColor,
} = canvasState;
const {
dragAndDropTextData,
handleCanvasMouseDown,
handleCanvasMouseMove,
handleCanvasMouseUp,
handleCanvasMouseLeave,
handleCanvasOffsetReset,
} = useDragAndDropText(+canvasWidth, +canvasHeight);

const getLineWidthByStrokeType = () => {
const strokeObj = {
None: 0,
Thin: 3,
Normal: 5,
Thick: 7,
} as { [key: string]: number };

return strokeObj[fontStrokeType];
};

const getMultiLinePosition = (
linesLength: number,
lineHeight: number,
idx: number
) => {
const { offsetX, offsetY } = dragAndDropTextData;
const centerX = +canvasWidth / 2;
const centerY = +canvasHeight / 2;

const x = offsetX ? offsetX : centerX;
const y = offsetY
? offsetY - ((linesLength - 1) * lineHeight) / 2 + idx * lineHeight
: centerY - ((linesLength - 1) * lineHeight) / 2 + idx * lineHeight;

return { x, y };
};

const setFontStroke = (ctx: CanvasRenderingContext2D, line: string) => {
if (fontStrokeType === 'None') return;

ctx.lineWidth = getLineWidthByStrokeType();
ctx.strokeStyle = `${strokeColor.hex}`;
ctx.strokeText(line, 0, 0);
};

const rotateCanvas = (ctx: CanvasRenderingContext2D) => {
const { offsetX, offsetY } = dragAndDropTextData;
const centerX = +canvasWidth / 2;
const centerY = +canvasHeight / 2;
const moveX = offsetX ? offsetX : centerX;
const moveY = offsetY ? offsetY : centerY;

ctx.translate(moveX, moveY);
ctx.rotate((+angle * Math.PI) / 180);
ctx.translate(-moveX, -moveY);
};

const fillCanvasMultiLineText = (
ctx: CanvasRenderingContext2D,
lines: string[]
) => {
const size = +fontSize.replace('px', '');
const lineHeight = size * 1.15;

lines.forEach((line, idx) => {
const { x, y } = getMultiLinePosition(lines.length, lineHeight, idx);

ctx.save();
ctx.translate(x, y);

setFontStroke(ctx, line);

ctx.fillStyle = fontColor.hex;
ctx.fillText(line, 0, 0);
ctx.restore();
};

useEffect(() => {
if (!ref.current) return;
const canvas = ref.current as HTMLCanvasElement;
const ctx = canvas.getContext('2d');

if (ctx) {
ctx.save();

if (isBlur) ctx.filter = 'blur(5px)'; // (*)
if (selectedImage) {
ctx.drawImage(selectedImage, 0, 0);
} else {
ctx.fillStyle = bgColor.hex;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}

ctx.restore();
setCanvasText(ctx);
}
}, [bgColor, fontColor, strokeColor, canvasState, dragAndDropTextData]);

useEffect(() => {
handleCanvasOffsetReset();
}, [selectedImage]);

return (
<S.CanvasWrapper>
<canvas
ref={ref}
width={+canvasWidth}
height={+canvasHeight}
onMouseDown={(e) => !isBlockEvent && handleCanvasMouseDown(e)}
onMouseMove={handleCanvasMouseMove}
onMouseUp={handleCanvasMouseUp}
onMouseLeave={handleCanvasMouseLeave}
/>
</S.CanvasWrapper>
);
}
);
});
};

const setCanvasText = (ctx: CanvasRenderingContext2D) => {
const lines = value.split('\n');
const size = +fontSize.replace('px', '');

ctx.font = `${size}px ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

ctx.save();

rotateCanvas(ctx);
fillCanvasMultiLineText(ctx, lines);

ctx.restore();
};

const fillBackground = (canvas: HTMLCanvasElement) => {
const ctx = canvas.getContext('2d');

if (!ctx) return;
if (selectedImage) {
if (isBlur) ctx.filter = 'blur(5px)';
ctx.drawImage(selectedImage, 0, 0);
return;
}
ctx.fillStyle = bgColor.hex;
ctx.fillRect(0, 0, canvas.width, canvas.height);
};

useEffect(() => {
if (!ref.current) return;
const canvas = ref.current as HTMLCanvasElement;
const ctx = canvas.getContext('2d');

if (!ctx) return;

ctx.save();
fillBackground(canvas);
ctx.restore();
setCanvasText(ctx);
}, [canvasState, dragAndDropTextData]);

useEffect(() => {
handleCanvasOffsetReset();
}, [selectedImage]);

return (
<S.CanvasWrapper>
<canvas
ref={ref}
width={+canvasWidth}
height={+canvasHeight}
onMouseDown={(e) => !isBlockEvent && handleCanvasMouseDown(e)}
onMouseMove={handleCanvasMouseMove}
onMouseUp={handleCanvasMouseUp}
onMouseLeave={handleCanvasMouseLeave}
/>
</S.CanvasWrapper>
);
});

Canvas.displayName = 'Search';

Expand Down
43 changes: 43 additions & 0 deletions src/components/Inputs/InputRange/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import TGInputText from '../../TGInputText';
import React, { ComponentProps, useMemo } from 'react';
import * as S from './styled';

interface InputRangeProps extends ComponentProps<'input'> {
value: string;
min: number;
max: number;
label: string;
}

const InputRange = ({
label,
name,
min,
max,
value,
onChange,
}: InputRangeProps) => {
const backgroundSize = useMemo(() => {
if (value === '-') return '50% 100%';
return ((+value - min) * 100) / (max - min) + '% 100%';
}, [min, max, value]);

return (
<S.InputRangeWrapper>
<S.InputLabelRangeContainer>
<label htmlFor={name}>{label}</label>
<S.StyledInputRange
type="range"
min={min}
max={max}
value={value}
onChange={onChange}
backgroundSize={backgroundSize}
/>
</S.InputLabelRangeContainer>
<TGInputText width={60} name={name} value={value} onChange={onChange} />
</S.InputRangeWrapper>
);
};

export default InputRange;
Loading

0 comments on commit 8d30b3b

Please sign in to comment.