From 9e05bb3287a7a1d38a33f5dfa3511a68fbc33ce3 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Wed, 26 Feb 2025 21:17:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=80=89=E6=8B=A9=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 2 +- src/module/render/components/selection.tsx | 83 ++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/module/render/components/selection.tsx diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 16d3011..8429642 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -313,7 +313,7 @@ export abstract class GraphicItemBase this.checkMode(GraphicModeProp.Stroke, nextValue); return true; case 'strokeAndFill': - if (!this.assertType(nextValue, 'number', key)) return false; + if (!this.assertType(nextValue, 'boolean', key)) return false; this.checkMode(GraphicModeProp.StrokeAndFill, nextValue); return true; case 'fillRule': diff --git a/src/module/render/components/selection.tsx b/src/module/render/components/selection.tsx new file mode 100644 index 0000000..2813a16 --- /dev/null +++ b/src/module/render/components/selection.tsx @@ -0,0 +1,83 @@ +import { DefaultProps, ElementLocator, onTick } from '@/core/render'; +import { computed, defineComponent } from 'vue'; +import { SetupComponentOptions } from './types'; +import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; +import { transitioned } from '../use'; +import { hyper } from 'mutate-animate'; + +export interface SelectionProps extends DefaultProps { + loc: ElementLocator; + color?: CanvasStyle; + border?: CanvasStyle; + winskin?: ImageIds; + /** 选择图标的不透明度范围 */ + alphaRange?: [number, number]; +} + +const selectionProps = { + props: ['loc', 'color', 'border', 'winskin', 'alphaRange'] +} satisfies SetupComponentOptions; + +export const Selection = defineComponent(props => { + const minAlpha = computed(() => props.alphaRange?.[0] ?? 0.25); + const maxAlpha = computed(() => props.alphaRange?.[1] ?? 0.55); + const alpha = transitioned(minAlpha.value, 2000, hyper('sin', 'in-out'))!; + + const isWinskin = computed(() => !!props.winskin); + const winskinImage = computed(() => + isWinskin.value ? core.material.images.images[props.winskin!] : null + ); + const fixedLoc = computed(() => { + const [x = 0, y = 0, width = 200, height = 200] = props.loc; + return [x + 1, y + 1, width - 2, height - 2]; + }); + + const renderWinskin = (canvas: MotaOffscreenCanvas2D) => { + const ctx = canvas.ctx; + const image = winskinImage.value; + if (!image) return; + const [, , width = 200, height = 200] = props.loc; + // 背景 + ctx.drawImage(image, 130, 66, 28, 28, 2, 2, width - 4, height - 4); + // 四个角 + ctx.drawImage(image, 128, 64, 2, 2, 0, 0, 2, 2); + ctx.drawImage(image, 158, 64, 2, 2, width - 2, 0, 2, 2); + ctx.drawImage(image, 128, 94, 2, 2, 0, height - 2, 2, 2); + ctx.drawImage(image, 158, 94, 2, 2, width - 2, height - 2, 2, 2); + // 四条边 + ctx.drawImage(image, 130, 64, 28, 2, 2, 0, width - 4, 2); + ctx.drawImage(image, 130, 94, 28, 2, 2, height - 2, width - 4, 2); + ctx.drawImage(image, 128, 66, 2, 28, 0, 2, 2, height - 4); + ctx.drawImage(image, 158, 66, 2, 28, width - 2, 2, 2, height - 4); + }; + + onTick(() => { + if (alpha.value === maxAlpha.value) { + alpha.set(minAlpha.value); + } + if (alpha.value === minAlpha.value) { + alpha.set(maxAlpha.value); + } + }); + + return () => + isWinskin.value ? ( + + ) : ( + + ); +}, selectionProps);