feat: 页码 & chore: 暂时移除 cursor 属性

This commit is contained in:
unanmed 2025-02-22 20:46:56 +08:00
parent 9588340b11
commit 06abef2595
7 changed files with 357 additions and 88 deletions

View File

@ -271,9 +271,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
/** 不透明度 */
alpha: number = 1;
/** 鼠标覆盖在此元素上时的光标样式 */
cursor: string = 'auto';
get x() {
return this._transform.x;
}
@ -1152,11 +1149,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
this.setAnchor(nextValue[0] as number, nextValue[1] as number);
return;
}
case 'cursor': {
if (!this.assertType(nextValue, 'string', key)) return;
this.cursor = nextValue;
return;
}
case 'scale': {
if (!this.assertType(nextValue, Array, key)) return;
this._transform.setScale(

View File

@ -5,6 +5,57 @@ import { ElementNamespace, ComponentInternalInstance } from 'vue';
import { clamp, isNil } from 'lodash-es';
import { logger } from '@/core/common/logger';
export type CircleParams = [
cx?: number,
cy?: number,
radius?: number,
start?: number,
end?: number
];
export type EllipseParams = [
cx?: number,
cy?: number,
radiusX?: number,
radiusY?: number,
start?: number,
end?: number
];
export type LineParams = [x1: number, y1: number, x2: number, y2: number];
export type BezierParams = [
sx: number,
sy: number,
cp1x: number,
cp1y: number,
cp2x: number,
cp2y: number,
ex: number,
ey: number
];
export type QuadParams = [
sx: number,
sy: number,
cpx: number,
cpy: number,
ex: number,
ey: number
];
export type RectRCircleParams = [
r1: number,
r2?: number,
r3?: number,
r4?: number
];
export type RectREllipseParams = [
rx1: number,
ry1: number,
rx2?: number,
ry2?: number,
rx3?: number,
ry3?: number,
rx4?: number,
ry4?: number
];
export interface ILineProperty {
/** 线宽 */
lineWidth: number;
@ -376,18 +427,21 @@ export class Circle extends GraphicItemBase {
if (!this.assertType(nextValue, 'number', key)) return;
this.setAngle(this.start, nextValue);
return;
case 'circle':
if (!this.assertType(nextValue, Array, key)) return;
if (!isNil(nextValue[0])) {
this.setRadius(nextValue[0] as number);
case 'circle': {
const value = nextValue as CircleParams;
if (!this.assertType(value, Array, key)) return;
const [cx, cy, radius, start, end] = value;
if (!isNil(cx) && !isNil(cy)) {
this.pos(cx, cy);
}
if (!isNil(nextValue[1]) && !isNil(nextValue[2])) {
this.setAngle(
nextValue[1] as number,
nextValue[2] as number
);
if (!isNil(radius)) {
this.setRadius(radius);
}
if (!isNil(start) && !isNil(end)) {
this.setAngle(start, end);
}
return;
}
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
@ -464,21 +518,21 @@ export class Ellipse extends GraphicItemBase {
if (!this.assertType(nextValue, 'number', key)) return;
this.setAngle(this.start, nextValue);
return;
case 'ellipse':
if (!this.assertType(nextValue, Array, key)) return;
if (!isNil(nextValue[0]) && !isNil(nextValue[1])) {
this.setRadius(
nextValue[0] as number,
nextValue[1] as number
);
case 'ellipse': {
const value = nextValue as EllipseParams;
if (!this.assertType(value, Array, key)) return;
const [cx, cy, radiusX, radiusY, start, end] = value;
if (!isNil(cx) && !isNil(cy)) {
this.pos(cx, cy);
}
if (!isNil(nextValue[2]) && !isNil(nextValue[3])) {
this.setAngle(
nextValue[2] as number,
nextValue[3] as number
);
if (!isNil(radiusX) && !isNil(radiusY)) {
this.setRadius(radiusX, radiusY);
}
if (!isNil(start) && !isNil(end)) {
this.setAngle(start, end);
}
return;
}
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
@ -858,23 +912,6 @@ export const enum RectRCorner {
BottomLeft
}
export type RectRCircleParams = [
r1: number,
r2?: number,
r3?: number,
r4?: number
];
export type RectREllipseParams = [
rx1: number,
ry1: number,
rx2?: number,
ry2?: number,
rx3?: number,
ry3?: number,
rx4?: number,
ry4?: number
];
export class RectR extends GraphicItemBase {
/** 圆角属性,四元素数组,每个元素是一个二元素数组,表示这个角的半径,顺序为 左上,右上,右下,左下 */
readonly corner: [radiusX: number, radiusY: number][] = [

View File

@ -107,10 +107,11 @@ export class Text extends RenderItem<ETextEvent> {
*
*/
calBox() {
const { width, fontBoundingBoxAscent } = this.measure();
const { width, actualBoundingBoxAscent, actualBoundingBoxDescent } =
this.measure();
this.length = width;
this.descent = fontBoundingBoxAscent;
this.size(width, fontBoundingBoxAscent);
this.descent = actualBoundingBoxAscent;
this.size(width, actualBoundingBoxAscent + actualBoundingBoxDescent);
}
patchProp(

View File

@ -450,9 +450,7 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
return this.target.canvas;
}
hoverElement(element: RenderItem): void {
this.target.canvas.style.cursor = element.cursor;
}
hoverElement(_element: RenderItem): void {}
destroy() {
super.destroy();

View File

@ -7,7 +7,12 @@ import {
} from '../preset/layer';
import type { EnemyCollection } from '@/game/enemy/damage';
import {
BezierParams,
CircleParams,
EllipseParams,
ILineProperty,
LineParams,
QuadParams,
RectRCircleParams,
RectREllipseParams
} from '../preset/graphics';
@ -40,7 +45,6 @@ export interface BaseProps {
id?: string;
alpha?: number;
composite?: GlobalCompositeOperation;
cursor?: string;
/**
* `[横坐标纵坐标宽度高度x锚点y锚点]`
* x锚点与y锚点
@ -132,33 +136,6 @@ export interface GraphicPropsBase extends BaseProps, Partial<ILineProperty> {
strokeStyle?: CanvasStyle;
}
export type CircleParams = [radius?: number, start?: number, end?: number];
export type EllipseParams = [
radiusX?: number,
radiusY?: number,
start?: number,
end?: number
];
export type LineParams = [x1: number, y1: number, x2: number, y2: number];
export type BezierParams = [
sx: number,
sy: number,
cp1x: number,
cp1y: number,
cp2x: number,
cp2y: number,
ex: number,
ey: number
];
export type QuadParams = [
sx: number,
sy: number,
cpx: number,
cpy: number,
ex: number,
ey: number
];
export interface RectProps extends GraphicPropsBase {}
export interface CirclesProps extends GraphicPropsBase {

View File

@ -0,0 +1,255 @@
import {
computed,
defineComponent,
nextTick,
onMounted,
ref,
SlotsType,
VNode,
watch
} from 'vue';
import { SetupComponentOptions } from './types';
import { clamp } from 'lodash-es';
import { ElementLocator } from '@/core/render';
/** 圆角矩形页码距离容器的边框大小,与 pageSize 相乘 */
const RECT_PAD = 0.1;
export interface PageProps {
/** 共有多少页 */
pages: number;
/** 页码组件的定位 */
loc: ElementLocator;
/** 页码的字体大小,默认为 14 */
pageSize?: number;
}
export interface PageExpose {
/**
*
* @param page 1
*/
changePage(page: number): void;
}
type PageSlots = SlotsType<{
default: (page: number) => VNode | VNode[];
}>;
const pageProps = {
props: ['pages', 'loc', 'pageSize']
} satisfies SetupComponentOptions<PageProps, {}, string, PageSlots>;
export const Page = defineComponent<PageProps, {}, string, PageSlots>(
(props, { slots, expose }) => {
const nowPage = ref(1);
// 五个元素的位置
const leftLoc = ref<ElementLocator>([]);
const leftPageLoc = ref<ElementLocator>([]);
const nowPageLoc = ref<ElementLocator>([]);
const rightPageLoc = ref<ElementLocator>([]);
const rightLoc = ref<ElementLocator>([]);
/** 内容的位置 */
const contentLoc = ref<ElementLocator>([]);
/** 页码容器的位置 */
const pageLoc = ref<ElementLocator>([]);
/** 页码的矩形框的位置 */
const rectLoc = ref<ElementLocator>([0, 0, 0, 0]);
/** 页面文字的位置 */
const textLoc = ref<ElementLocator>([0, 0, 0, 0]);
// 两个监听的参数
const leftArrow = ref<Path2D>(new Path2D());
const rightArrow = ref<Path2D>(new Path2D());
const isFirst = computed(() => nowPage.value === 1);
const isLast = computed(() => nowPage.value === props.pages);
const pageSize = computed(() => props.pageSize ?? 14);
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const round = computed(() => pageSize.value / 4);
const pageFont = computed(() => `${pageSize.value}px normal`);
// 左右箭头的颜色
const leftColor = computed(() => (isFirst.value ? '#666' : '#ddd'));
const rightColor = computed(() => (isLast.value ? '#666' : '#ddd'));
let updating = false;
const updatePagePos = () => {
if (updating) return;
updating = true;
nextTick(() => {
updating = false;
});
const pageH = pageSize.value + 8;
contentLoc.value = [0, 0, width.value, height.value - pageH];
pageLoc.value = [0, height.value - pageH, width.value, pageH];
const center = width.value / 2;
const size = pageSize.value * 1.5;
nowPageLoc.value = [center, 0, size, size, 0.5, 0];
leftPageLoc.value = [center - size * 1.5, 0, size, size, 0.5, 0];
leftLoc.value = [center - size * 3, 0, size, size, 0.5, 0];
rightPageLoc.value = [center + size * 1.5, 0, size, size, 0.5, 0];
rightLoc.value = [center + size * 3, 0, size, size, 0.5, 0];
};
const updateArrowPath = () => {
const rectSize = pageSize.value * 1.5;
const size = pageSize.value;
const pad = rectSize - size;
const left = new Path2D();
left.moveTo(size, pad);
left.lineTo(pad, rectSize / 2);
left.lineTo(size, rectSize - pad);
const right = new Path2D();
right.moveTo(pad, pad);
right.lineTo(size, rectSize / 2);
right.lineTo(pad, rectSize - pad);
leftArrow.value = left;
rightArrow.value = right;
};
const updateRectAndText = () => {
const size = pageSize.value * 1.5;
const pad = RECT_PAD * size;
rectLoc.value = [pad, pad, size - pad * 2, size - pad * 2];
textLoc.value = [size / 2, size / 2, void 0, void 0, 0.5, 0.5];
};
watch(pageSize, () => {
updatePagePos();
updateArrowPath();
updateRectAndText();
});
watch(
() => props.loc,
() => {
updatePagePos();
updateRectAndText();
}
);
/**
*
*/
const changePage = (page: number) => {
const target = clamp(page, 1, props.pages);
nowPage.value = target;
};
const lastPage = () => {
changePage(nowPage.value - 1);
};
const nextPage = () => {
changePage(nowPage.value + 1);
};
onMounted(() => {
updatePagePos();
updateArrowPath();
updateRectAndText();
});
expose({ changePage });
return () => {
return (
<container loc={props.loc}>
<container loc={contentLoc.value}>
{slots.default?.(nowPage.value)}
</container>
<container loc={pageLoc.value}>
<container loc={leftLoc.value} onClick={lastPage}>
<g-rectr
loc={rectLoc.value}
circle={[round.value]}
strokeStyle={leftColor.value}
lineWidth={1}
stroke
></g-rectr>
<g-path
path={leftArrow.value}
stroke
strokeStyle={leftColor.value}
lineWidth={1}
></g-path>
</container>
{!isFirst.value && (
<container
loc={leftPageLoc.value}
onClick={lastPage}
>
<g-rectr
loc={rectLoc.value}
circle={[round.value]}
strokeStyle="#ddd"
lineWidth={1}
stroke
></g-rectr>
<text
loc={textLoc.value}
text={(nowPage.value - 1).toString()}
font={pageFont.value}
></text>
</container>
)}
<container loc={nowPageLoc.value}>
<g-rectr
loc={rectLoc.value}
circle={[round.value]}
strokeStyle="#ddd"
fillStyle="#ddd"
lineWidth={1}
fill
stroke
></g-rectr>
<text
loc={textLoc.value}
text={nowPage.value.toString()}
fillStyle="#222"
font={pageFont.value}
></text>
</container>
{!isLast.value && (
<container
loc={rightPageLoc.value}
onClick={nextPage}
>
<g-rectr
loc={rectLoc.value}
circle={[round.value]}
strokeStyle="#ddd"
lineWidth={1}
stroke
></g-rectr>
<text
loc={textLoc.value}
text={(nowPage.value + 1).toString()}
font={pageFont.value}
></text>
</container>
)}
<container loc={rightLoc.value} onClick={nextPage}>
<g-rectr
loc={rectLoc.value}
circle={[round.value]}
strokeStyle={rightColor.value}
lineWidth={1}
stroke
></g-rectr>
<g-path
path={rightArrow.value}
stroke
strokeStyle={rightColor.value}
lineWidth={1}
></g-path>
</container>
</container>
</container>
);
};
},
pageProps
);

View File

@ -3,6 +3,7 @@ import { defineComponent } from 'vue';
import { SetupComponentOptions } from '../components';
import { ElementLocator } from '@/core/render';
import { Scroll } from '../components/scroll';
import { Page } from '../components/page';
export interface ILeftHeroStatus {
hp: number;
@ -91,7 +92,6 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
text={floorName}
loc={central(24)}
font={font1}
cursor="pointer"
></text>
<text text={s.lv} loc={central(54)} font={font1}></text>
<image image={hpIcon} loc={iconLoc(0)}></image>
@ -144,17 +144,11 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
font={font2}
fillStyle="#f88"
></text>
<text
text="技能树"
loc={central(396)}
font={font1}
cursor="pointer"
></text>
<text text="技能树" loc={central(396)} font={font1}></text>
<text
text="查看技能"
loc={central(428)}
font={font1}
cursor="pointer"
></text>
</container>
);
@ -170,6 +164,21 @@ export const RightStatusBar = defineComponent<StatusBarProps<IRightHeroStatus>>(
<container loc={p.loc}>
<g-rect loc={[0, 0, p.loc[2], p.loc[3]]} stroke></g-rect>
<Scroll loc={[0, 0, 180, 100]}></Scroll>
<Page loc={[0, 200, 180, 100]} pages={3}>
{(page: number) => {
switch (page) {
case 1: {
return <text text="测试"></text>;
}
case 2: {
return <text text="测试2"></text>;
}
case 3: {
return <text text="测试3"></text>;
}
}
}}
</Page>
</container>
);
};