Skip to content

Commit

Permalink
feat: add draw image tool (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
F-star committed Oct 25, 2024
1 parent a6deb40 commit 6b5a8de
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 8 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ English | [中文](./README_zh.md)

## Features

1. Creation and editing of graphics, including: rounded rectangles, ellipses, lines, paths (polyline), text, polygons, stars;
1. Creation and editing of graphics, including: rounded rectangle, ellipse, line, path, text, polygon, star;
2. Path editing using the pen tool, adjusting control points;
3. Support tools: selection tool, shape drawing tools, pen tool, canvas tool, hand tool;
3. Support tools: selection tool, graphics drawing tools, image tool, pen tool, canvas tool, hand tool;
4. Infinite canvas, with zoom and pan capabilities;
5. History, with undo and redo;
6. i18n;
7. Snap support, currently supports pixel grid snap and shape guide snap;
7. Snap support, currently supports pixel grid snap and graphics guide snap;
8. Keyboard shortcuts;
9. Copy and paste, supports cross-canvas copy and paste, alignment, and arrangement;
10. Layers panel, properties panel;
11. Group, Frame;
12. Multi-user collaborative editing (requires backend implementation);
13. Ruler;
14. Import and export JSON;
14. Import and export JSON data;
15. User settings;

Next Steps
Expand Down
2 changes: 1 addition & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

1. 图形的创建和编辑,包括:圆角矩形、椭圆、线、路径(多段线)、文本、多边形、星形;
2. 使用钢笔工具进行路径编辑,调整控制点;
3. 丰富的工具:选中工具、绘制图形工具、钢笔工具、画布工具、抓手工具;
3. 丰富的工具:选中工具、绘制图形工具、绘制图形工具、钢笔工具、画布工具、抓手工具;
4. 无限画布,可以缩放和拖拽画布;
5. 历史记录,可撤销重做;
6. 国际化;
Expand Down
90 changes: 90 additions & 0 deletions packages/core/src/tools/tool_draw_img.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { type IRect, normalizeRect } from '@suika/geo';

import { type SuikaEditor } from '../editor';
import { SuikaRect } from '../graphics';
import { PaintType } from '../paint';
import { DrawGraphicsTool } from './tool_draw_graphics';
import { type ITool } from './type';

interface ImgData {
url: string;
name: string;
}

const uploadImg = () => {
return new Promise<ImgData>((resolve) => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/*'; // only image

fileInput.onchange = (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
const src = e.target?.result as string;
setTimeout(() => {
resolve({ url: src, name: file.name });
});
};
reader.readAsDataURL(file);
};

fileInput.click();
});
};

const TYPE = 'drawImg';
const HOTKEY = '';

export class DrawImgTool extends DrawGraphicsTool implements ITool {
static override readonly type = TYPE;
static override readonly hotkey = HOTKEY;
override readonly type = TYPE;
override readonly hotkey = HOTKEY;

private imgData: ImgData | null = null;

constructor(editor: SuikaEditor) {
super(editor);
this.commandDesc = 'Add Image';
}

async enableActive() {
try {
const imgData = await uploadImg();
await this.editor.imgManager.addImg(imgData.url);
this.imgData = imgData;
return true;
} catch (error) {
return false;
}
}

protected override createGraphics(rect: IRect) {
rect = normalizeRect(rect);
const graphics = new SuikaRect(
{
objectName: this.imgData!.name,
width: rect.width,
height: rect.height,
fill: [
{
type: PaintType.Image,
attrs: {
src: this.imgData!.url,
},
},
],
},
{
advancedAttrs: {
x: rect.x,
y: rect.y,
},
doc: this.editor.doc,
},
);
return graphics;
}
}
17 changes: 14 additions & 3 deletions packages/core/src/tools/tool_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type IKey } from '../key_binding_manager';
import { DragCanvasTool } from './tool_drag_canvas';
import { DrawEllipseTool } from './tool_draw_ellipse';
import { DrawFrameTool } from './tool_draw_frame';
import { DrawImgTool } from './tool_draw_img';
import { DrawLineTool } from './tool_draw_line';
import { DrawPathTool } from './tool_draw_path';
import { DrawRectTool } from './tool_draw_rect';
Expand Down Expand Up @@ -46,6 +47,7 @@ export class ToolManager {
this.registerToolCtor(DrawFrameTool);
this.registerToolCtor(DrawRectTool);
this.registerToolCtor(DrawEllipseTool);
this.registerToolCtor(DrawImgTool);
this.registerToolCtor(DrawLineTool);
this.registerToolCtor(DrawTextTool);
this.registerToolCtor(DragCanvasTool);
Expand All @@ -60,6 +62,7 @@ export class ToolManager {
DrawFrameTool.type,
DrawRectTool.type,
DrawEllipseTool.type,
DrawImgTool.type,
DrawPathTool.type,
PencilTool.type,
DrawLineTool.type,
Expand Down Expand Up @@ -265,7 +268,7 @@ export class ToolManager {
this._unbindEvent = noop;
this.unbindHotkey();
}
setActiveTool(toolName: string) {
async setActiveTool(toolName: string) {
if (!this.enableSwitchTool || this.getActiveToolName() === toolName) {
return;
}
Expand All @@ -275,12 +278,20 @@ export class ToolManager {
return;
}

const prevTool = this.currentTool;
const currentToolCtor = this.toolCtorMap.get(toolName) || null;
if (!currentToolCtor) {
throw new Error(`tool "${toolName}" is not registered`);
}
const currentTool = (this.currentTool = new currentToolCtor(this.editor));
const currentTool = new currentToolCtor(this.editor);

if (currentTool.enableActive) {
const canActive = await currentTool.enableActive();
if (!canActive) {
return;
}
}
const prevTool = this.currentTool;
this.currentTool = currentTool;

prevTool && prevTool.onInactive();
this.setCursorWhenActive();
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/tools/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface ITool extends IBaseTool {
hotkey: string | IKey;
type: string;
cursor: ICursor;

enableActive?: () => Promise<boolean>;
onMoveExcludeDrag: (event: PointerEvent, isOutsideCanvas: boolean) => void;
getDragBlockStep?: () => number;
}
Expand Down
19 changes: 19 additions & 0 deletions packages/icons/src/icons/tool/image-outlined.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

export const ImageOutlined = React.memo(() => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18 5H5V13.6849L8.46807 9.78333L17.1983 18H18V5ZM5 18V15.1901L8.53193 11.2167L15.7392 18H5ZM4 4V19H19V4H4ZM16 9.5C16 10.3284 15.3284 11 14.5 11C13.6716 11 13 10.3284 13 9.5C13 8.67157 13.6716 8 14.5 8C15.3284 8 16 8.67157 16 9.5ZM17 9.5C17 10.8807 15.8807 12 14.5 12C13.1193 12 12 10.8807 12 9.5C12 8.11929 13.1193 7 14.5 7C15.8807 7 17 8.11929 17 9.5Z"
/>
</svg>
);
});
1 change: 1 addition & 0 deletions packages/icons/src/icons/tool/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './ellipse-outlined';
export * from './frame-outline';
export * from './hand-outlined';
export * from './image-outlined';
export * from './line-outlined';
export * from './menu-outlined';
export * from './polygon-outlined';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
EllipseOutlined,
FrameOutlined,
HandOutlined,
ImageOutlined,
LineOutlined,
PencilOutlined,
PenOutlined,
Expand Down Expand Up @@ -86,6 +87,12 @@ export const ToolBar = () => {
intlId: 'tool.ellipse',
icon: <EllipseOutlined />,
},
drawImg: {
name: 'drawImg',
hotkey: '',
intlId: 'tool.image',
icon: <ImageOutlined />,
},
pathSelect: {
name: 'pathSelect',
hotkey: 'V',
Expand Down
1 change: 1 addition & 0 deletions packages/suika/src/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"tool.frame": "Frame",
"tool.rectangle": "Rectangle",
"tool.ellipse": "Ellipse",
"tool.image": "Image",
"tool.pen": "Pen",
"tool.line": "Line",
"tool.polygon": "Polygon",
Expand Down
1 change: 1 addition & 0 deletions packages/suika/src/locale/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"tool.frame": "画板",
"tool.rectangle": "矩形",
"tool.ellipse": "",
"tool.image": "图片",
"tool.pen": "钢笔",
"tool.line": "直线",
"tool.polygon": "多边形",
Expand Down

0 comments on commit 6b5a8de

Please sign in to comment.