feat(editor): add highlighter (#10573)

Closes: [BS-2909](https://linear.app/affine-design/issue/BS-2909/新增highlighter)

### What's Changed!

Currently the highlighter tool is very similar to brush, but for the future, it's a standalone module.

* Added `Highlighter` element model
* Added `Highlighter` tool
* Added `Highlighter` entry to the global toolbar
This commit is contained in:
fundon
2025-03-27 08:53:26 +00:00
parent 676a8d653f
commit 2c4278058b
36 changed files with 1667 additions and 483 deletions

View File

@@ -1,6 +1,9 @@
import { edgelessTextToolbarExtension } from '@blocksuite/affine-block-edgeless-text';
import { frameToolbarExtension } from '@blocksuite/affine-block-frame';
import { brushToolbarExtension } from '@blocksuite/affine-gfx-brush';
import {
brushToolbarExtension,
highlighterToolbarExtension,
} from '@blocksuite/affine-gfx-brush';
import { connectorToolbarExtension } from '@blocksuite/affine-gfx-connector';
import { groupToolbarExtension } from '@blocksuite/affine-gfx-group';
import { mindmapToolbarExtension } from '@blocksuite/affine-gfx-mindmap';
@@ -19,6 +22,8 @@ export const EdgelessElementToolbarExtension: ExtensionType[] = [
brushToolbarExtension,
highlighterToolbarExtension,
connectorToolbarExtension,
mindmapToolbarExtension,

View File

@@ -4,7 +4,11 @@ import {
PresentTool,
} from '@blocksuite/affine-block-frame';
import { ConnectionOverlay } from '@blocksuite/affine-block-surface';
import { BrushTool, EraserTool } from '@blocksuite/affine-gfx-brush';
import {
BrushTool,
EraserTool,
HighlighterTool,
} from '@blocksuite/affine-gfx-brush';
import {
ConnectorFilter,
ConnectorTool,
@@ -45,6 +49,7 @@ export const EdgelessToolExtension: ExtensionType[] = [
FrameTool,
LassoTool,
PresentTool,
HighlighterTool,
];
export const EdgelessEditExtensions: ExtensionType[] = [

View File

@@ -2,6 +2,7 @@ import {
BrushElementModel,
ConnectorElementModel,
GroupElementModel,
HighlighterElementModel,
MindmapElementModel,
ShapeElementModel,
TextElementModel,
@@ -16,12 +17,14 @@ export const elementsCtorMap = {
brush: BrushElementModel,
text: TextElementModel,
mindmap: MindmapElementModel,
highlighter: HighlighterElementModel,
};
export {
BrushElementModel,
ConnectorElementModel,
GroupElementModel,
HighlighterElementModel,
MindmapElementModel,
ShapeElementModel,
SurfaceElementModel,
@@ -35,6 +38,7 @@ export enum CanvasElementType {
MINDMAP = 'mindmap',
SHAPE = 'shape',
TEXT = 'text',
HIGHLIGHTER = 'highlighter',
}
export type ElementModelMap = {
@@ -44,6 +48,7 @@ export type ElementModelMap = {
['text']: TextElementModel;
['group']: GroupElementModel;
['mindmap']: MindmapElementModel;
['highlighter']: HighlighterElementModel;
};
export function isCanvasElementType(type: string): type is CanvasElementType {

View File

@@ -0,0 +1,34 @@
import {
DefaultTheme,
type HighlighterElementModel,
} from '@blocksuite/affine-model';
import type { CanvasRenderer } from '../../canvas-renderer.js';
export function highlighter(
model: HighlighterElementModel,
ctx: CanvasRenderingContext2D,
matrix: DOMMatrix,
renderer: CanvasRenderer
) {
const {
rotate,
deserializedXYWH: [, , w, h],
} = model;
const cx = w / 2;
const cy = h / 2;
ctx.setTransform(
matrix.translateSelf(cx, cy).rotateSelf(rotate).translateSelf(-cx, -cy)
);
const color = renderer.getColorValue(
model.color,
DefaultTheme.hightlighterColor,
true
);
ctx.fillStyle = color;
ctx.fill(new Path2D(model.commands));
}

View File

@@ -6,6 +6,7 @@ import type { CanvasRenderer } from '../canvas-renderer.js';
import { brush } from './brush/index.js';
import { connector } from './connector/index.js';
import { group } from './group/index.js';
import { highlighter } from './highlighter/index.js';
import { mindmap } from './mindmap.js';
import { shape } from './shape/index.js';
import { text } from './text/index.js';
@@ -24,6 +25,7 @@ export type ElementRenderer<
export const elementRenderers = {
brush,
highlighter,
connector,
group,
shape,