feat:V2.5.2 颜色找规律
This commit is contained in:
@@ -28,7 +28,8 @@
|
|||||||
"gridDrawing/gridDrawing",
|
"gridDrawing/gridDrawing",
|
||||||
"shape/shape",
|
"shape/shape",
|
||||||
"positionColoring/positionColoring",
|
"positionColoring/positionColoring",
|
||||||
"shapeSymbol/shapeSymbol"
|
"shapeSymbol/shapeSymbol",
|
||||||
|
"colorPattern/colorPattern"
|
||||||
],
|
],
|
||||||
"independent": false
|
"independent": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ App<IAppOption>({
|
|||||||
if (env !== 'release') {
|
if (env !== 'release') {
|
||||||
const printConfig =
|
const printConfig =
|
||||||
wx.getStorageSync('printConfig') || defaultPrintConfig;
|
wx.getStorageSync('printConfig') || defaultPrintConfig;
|
||||||
// 开发环境,设置为 LogoImage
|
|
||||||
printConfig.header = 'LogoImage';
|
|
||||||
this.globalData.printConfig = printConfig;
|
this.globalData.printConfig = printConfig;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ export const FOCUS_FUNCTION_TYPES: FocusFunctionType[] = [
|
|||||||
desc: '观察卡片位置,在对应的方格中涂上颜色',
|
desc: '观察卡片位置,在对应的方格中涂上颜色',
|
||||||
icon: '📍',
|
icon: '📍',
|
||||||
},
|
},
|
||||||
|
// 颜色找规律
|
||||||
|
{
|
||||||
|
id: 'color-pattern',
|
||||||
|
page: 'colorPattern',
|
||||||
|
title: '颜色找规律',
|
||||||
|
desc: '观察颜色规律,在空白图形中涂上颜色',
|
||||||
|
icon: '🎨',
|
||||||
|
},
|
||||||
// 格子仿画
|
// 格子仿画
|
||||||
{
|
{
|
||||||
id: 'grid-drawing-3x3',
|
id: 'grid-drawing-3x3',
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"navigationBarTitleText": "颜色找规律",
|
||||||
|
"navigationBarBackgroundColor": "#FFD719",
|
||||||
|
"homeButton": true,
|
||||||
|
"backgroundColor": "#F6F6F6",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"usingComponents": {
|
||||||
|
"toy-button": "../../ui/button/button",
|
||||||
|
"share-guide-popup": "../../components/share-guide-popup/share-guide-popup",
|
||||||
|
"math-bottom-buttons": "../../components/math-bottom-buttons/math-bottom-buttons"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import ColorPatternDraw from '../shared/service/colorPatternDraw';
|
||||||
|
import { createFocusPage } from '../shared/common/focusPageMixin';
|
||||||
|
import { ColorPatternData } from '../shared/service/colorPatternDraw';
|
||||||
|
import { SHAPE_SYMBOL_SHAPES } from '../shared/shapes/shapeSymbolShapes';
|
||||||
|
import { getNumberColors } from '../../constants/colors';
|
||||||
|
|
||||||
|
createFocusPage({
|
||||||
|
canvas: null as Canvas | null,
|
||||||
|
ctx: null as RenderingContext | null,
|
||||||
|
boxHeight: 0,
|
||||||
|
boxWidth: 0,
|
||||||
|
drawService: null as ColorPatternDraw | null,
|
||||||
|
gridData: null as ColorPatternData | null,
|
||||||
|
|
||||||
|
data: {
|
||||||
|
pageTitle: '颜色找规律',
|
||||||
|
functionId: '',
|
||||||
|
hasContent: false,
|
||||||
|
showShareDialog: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(options: { id?: string }) {
|
||||||
|
const functionId = options.id || 'color-pattern';
|
||||||
|
this.setData({
|
||||||
|
functionId,
|
||||||
|
});
|
||||||
|
this.initPageInfo(functionId, '颜色找规律');
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.initCanvas({
|
||||||
|
createDrawService: (
|
||||||
|
canvas: Canvas,
|
||||||
|
ctx: RenderingContext,
|
||||||
|
options?: Record<string, any>,
|
||||||
|
) => {
|
||||||
|
return new ColorPatternDraw(canvas, ctx, options);
|
||||||
|
},
|
||||||
|
drawServiceOptions: {
|
||||||
|
title: this.data.pageTitle,
|
||||||
|
subTitle: '观察颜色规律,在空白图形中涂上颜色',
|
||||||
|
functionId: this.data.functionId,
|
||||||
|
},
|
||||||
|
onCanvasReady: () => {
|
||||||
|
// 初始随机生成
|
||||||
|
this.onRandom();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制Canvas内容
|
||||||
|
*/
|
||||||
|
async drawCanvas() {
|
||||||
|
if (!this.ctx || !this.drawService || !this.gridData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.drawService.draw(this.gridData);
|
||||||
|
this.setData({ hasContent: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('绘制失败:', error);
|
||||||
|
this.setData({ hasContent: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机生成
|
||||||
|
*/
|
||||||
|
onRandom() {
|
||||||
|
// 从9种图形中随机选择8个不同的图形(每组使用不同的图形)
|
||||||
|
const allShapes = [...SHAPE_SYMBOL_SHAPES];
|
||||||
|
const shuffledShapes = allShapes.sort(() => Math.random() - 0.5);
|
||||||
|
const selectedShapes = shuffledShapes.slice(0, 8); // 选择8个不同的图形
|
||||||
|
|
||||||
|
// 获取所有可用颜色
|
||||||
|
const allColors = getNumberColors();
|
||||||
|
|
||||||
|
// 生成8组数据
|
||||||
|
const groups: Array<{
|
||||||
|
shapeId: string;
|
||||||
|
colors: Array<string | null>; // 前4个有颜色,后6个为null
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
for (let groupIndex = 0; groupIndex < 8; groupIndex++) {
|
||||||
|
// 每一组使用不同的图形
|
||||||
|
const selectedShape = selectedShapes[groupIndex];
|
||||||
|
|
||||||
|
// 每一行独立选择2种或3种颜色
|
||||||
|
const colorCount = Math.random() < 0.5 ? 2 : 3; // 随机选择2种或3种
|
||||||
|
const shuffledColors = [...allColors].sort(
|
||||||
|
() => Math.random() - 0.5,
|
||||||
|
);
|
||||||
|
const selectedColors = shuffledColors.slice(0, colorCount);
|
||||||
|
|
||||||
|
// 生成前4个图形的颜色规律
|
||||||
|
// 从选中的颜色中随机选择,形成规律(可以重复)
|
||||||
|
// 但至少保证有两种不同的颜色,不能4个都相同
|
||||||
|
const patternColors: string[] = [];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
// 随机从选中的颜色中选择一种
|
||||||
|
const randomColor =
|
||||||
|
selectedColors[
|
||||||
|
Math.floor(Math.random() * selectedColors.length)
|
||||||
|
];
|
||||||
|
patternColors.push(randomColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否只有一种颜色,如果是则确保至少有两种颜色
|
||||||
|
const uniqueColors = new Set(patternColors);
|
||||||
|
if (uniqueColors.size === 1) {
|
||||||
|
// 如果4个都是同一种颜色,随机选择一个位置替换为另一种颜色
|
||||||
|
const currentColor = patternColors[0];
|
||||||
|
const otherColors = selectedColors.filter(
|
||||||
|
(c) => c !== currentColor,
|
||||||
|
);
|
||||||
|
if (otherColors.length > 0) {
|
||||||
|
const randomIndex = Math.floor(
|
||||||
|
Math.random() * patternColors.length,
|
||||||
|
);
|
||||||
|
const randomOtherColor =
|
||||||
|
otherColors[
|
||||||
|
Math.floor(Math.random() * otherColors.length)
|
||||||
|
];
|
||||||
|
patternColors[randomIndex] = randomOtherColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后6个图形留空(null)
|
||||||
|
const emptyColors: Array<string | null> = new Array(6).fill(null);
|
||||||
|
|
||||||
|
groups.push({
|
||||||
|
shapeId: selectedShape.id,
|
||||||
|
colors: [...patternColors, ...emptyColors],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gridData = {
|
||||||
|
groups,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.drawCanvas();
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<view class="page-container">
|
||||||
|
<view class="wrapper">
|
||||||
|
<text class="wrapper-title">预览打印效果</text>
|
||||||
|
|
||||||
|
<!-- 预览打印效果 -->
|
||||||
|
<view id="canvasWrapper" class="canvas-wrapper">
|
||||||
|
<canvas
|
||||||
|
type="2d"
|
||||||
|
id="canvasContent"
|
||||||
|
class="canvas-content"
|
||||||
|
style="width:{{boxWidth}}px;height:{{boxHeight}}px" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 随机生成按钮 -->
|
||||||
|
<view class="random-button-area">
|
||||||
|
<toy-button
|
||||||
|
class="random-button"
|
||||||
|
type="primary"
|
||||||
|
bind:click="onRandom"
|
||||||
|
width="100%"
|
||||||
|
height="80rpx"
|
||||||
|
icon="refresh"
|
||||||
|
icon-class-prefix="toy-icon">
|
||||||
|
随机生成
|
||||||
|
</toy-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="empty"></view>
|
||||||
|
</view>
|
||||||
|
<math-bottom-buttons
|
||||||
|
disabled="{{!hasContent}}"
|
||||||
|
bind:share="onShareAppMessage"
|
||||||
|
bind:export="exportToPrint" />
|
||||||
|
<share-guide-popup
|
||||||
|
show="{{showShareDialog}}"
|
||||||
|
bind:onClose="onCloseShareDialog"
|
||||||
|
bind:onShareSuccess="onShareSuccess" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@import '../../base/baseDrawPage.wxss';
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/**
|
||||||
|
* 颜色找规律绘制服务
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BaseDrawService } from '../../../service/baseDraw';
|
||||||
|
import {
|
||||||
|
drawShapeSymbolShape,
|
||||||
|
DrawShapeOptions,
|
||||||
|
} from '../shapes/shapeSymbolShapes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色找规律数据
|
||||||
|
*/
|
||||||
|
export interface ColorPatternData {
|
||||||
|
/** 8组数据,每组包含图形ID和10个格子的颜色(前4个有颜色,后6个为null) */
|
||||||
|
groups: Array<{
|
||||||
|
shapeId: string;
|
||||||
|
colors: Array<string | null>; // 长度为10,前4个有颜色,后6个为null
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色找规律绘制服务
|
||||||
|
*/
|
||||||
|
class ColorPatternDraw extends BaseDrawService {
|
||||||
|
gridData: ColorPatternData | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
canvas: Canvas,
|
||||||
|
ctx: RenderingContext,
|
||||||
|
options?: Record<string, any>,
|
||||||
|
) {
|
||||||
|
super(canvas, ctx, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制颜色找规律内容
|
||||||
|
*/
|
||||||
|
async draw(gridData: ColorPatternData) {
|
||||||
|
if (!gridData || !gridData.groups) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setPrintConfig();
|
||||||
|
this.gridData = gridData;
|
||||||
|
this.clear();
|
||||||
|
this.setPaper();
|
||||||
|
|
||||||
|
// 绘制Header
|
||||||
|
if (this.headerType !== 'minimal') {
|
||||||
|
await this.drawHeader();
|
||||||
|
} else {
|
||||||
|
this.drawMiniHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制内容区域
|
||||||
|
this.drawDivider();
|
||||||
|
this.drawContent({
|
||||||
|
ctx: this.ctx,
|
||||||
|
gridData: this.gridData,
|
||||||
|
canvasWidth: this.canvasWidth,
|
||||||
|
startY: this.currentY,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制内容区域
|
||||||
|
*/
|
||||||
|
private drawContent(params: {
|
||||||
|
ctx: RenderingContext;
|
||||||
|
gridData: ColorPatternData;
|
||||||
|
canvasWidth: number;
|
||||||
|
startY: number;
|
||||||
|
}): void {
|
||||||
|
const { ctx, gridData, canvasWidth } = params;
|
||||||
|
let { startY } = params;
|
||||||
|
|
||||||
|
startY = startY + 25;
|
||||||
|
|
||||||
|
const margin = 40; // 左右边距
|
||||||
|
const cols = 10; // 每行10列
|
||||||
|
const cellSize = 50; // 每个格子的宽度
|
||||||
|
const gridWidth = cellSize * cols;
|
||||||
|
const groupSpacing = 40; // 每组之间的间距
|
||||||
|
|
||||||
|
// 计算起始X位置(居中)
|
||||||
|
const startX = margin + (canvasWidth - margin * 2 - gridWidth) / 2;
|
||||||
|
|
||||||
|
// 绘制8组
|
||||||
|
for (
|
||||||
|
let groupIndex = 0;
|
||||||
|
groupIndex < gridData.groups.length;
|
||||||
|
groupIndex++
|
||||||
|
) {
|
||||||
|
const group = gridData.groups[groupIndex];
|
||||||
|
if (!group) continue;
|
||||||
|
|
||||||
|
const groupY = startY + groupIndex * (cellSize + groupSpacing);
|
||||||
|
|
||||||
|
// 绘制网格线(只绘制这一行的网格)
|
||||||
|
this.drawGridLines(
|
||||||
|
startX,
|
||||||
|
groupY,
|
||||||
|
cellSize,
|
||||||
|
cellSize,
|
||||||
|
cols,
|
||||||
|
1, // 只有1行
|
||||||
|
);
|
||||||
|
|
||||||
|
// 绘制图形和颜色
|
||||||
|
for (let col = 0; col < cols; col++) {
|
||||||
|
const color = group.colors[col];
|
||||||
|
const colX = startX + col * cellSize;
|
||||||
|
const cellCenterX = colX + cellSize / 2;
|
||||||
|
const cellCenterY = groupY + cellSize / 2;
|
||||||
|
const shapeSize = 35;
|
||||||
|
|
||||||
|
if (color) {
|
||||||
|
// 前4个图形:绘制带颜色的图形
|
||||||
|
|
||||||
|
drawShapeSymbolShape(
|
||||||
|
ctx,
|
||||||
|
group.shapeId,
|
||||||
|
cellCenterX,
|
||||||
|
cellCenterY,
|
||||||
|
shapeSize,
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 根据图形ID绘制轮廓
|
||||||
|
this.drawShapeOutline(
|
||||||
|
ctx,
|
||||||
|
group.shapeId,
|
||||||
|
cellCenterX,
|
||||||
|
cellCenterY,
|
||||||
|
shapeSize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制图形轮廓(用于空白图形)
|
||||||
|
* 复用 shapeSymbolShapes.ts 中的绘制逻辑
|
||||||
|
*/
|
||||||
|
private drawShapeOutline(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
shapeId: string,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
): void {
|
||||||
|
const options: DrawShapeOptions = {
|
||||||
|
fillColor: null,
|
||||||
|
strokeColor: '#000',
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
};
|
||||||
|
// 使用新的调用方式,直接传入 options
|
||||||
|
drawShapeSymbolShape(ctx, shapeId, x, y, size, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ColorPatternDraw;
|
||||||
@@ -80,7 +80,7 @@ class PositionColoringDraw extends BaseDrawService {
|
|||||||
|
|
||||||
const margin = 40; // 左右边距
|
const margin = 40; // 左右边距
|
||||||
const gridSize = 3; // 3x3网格
|
const gridSize = 3; // 3x3网格
|
||||||
const cellSize = 65; // 每个格子的大小
|
const cellSize = 65; // 每个格子的宽度
|
||||||
const gridWidth = cellSize * gridSize;
|
const gridWidth = cellSize * gridSize;
|
||||||
const gridHeight = cellSize * gridSize;
|
const gridHeight = cellSize * gridSize;
|
||||||
|
|
||||||
@@ -91,12 +91,11 @@ class PositionColoringDraw extends BaseDrawService {
|
|||||||
|
|
||||||
// 绘制参考网格的网格线
|
// 绘制参考网格的网格线
|
||||||
this.drawGridLines(
|
this.drawGridLines(
|
||||||
ctx,
|
|
||||||
referenceGridX,
|
referenceGridX,
|
||||||
referenceGridY,
|
referenceGridY,
|
||||||
gridWidth,
|
|
||||||
gridHeight,
|
|
||||||
cellSize,
|
cellSize,
|
||||||
|
cellSize,
|
||||||
|
gridSize,
|
||||||
gridSize,
|
gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -105,7 +104,7 @@ class PositionColoringDraw extends BaseDrawService {
|
|||||||
const row = Math.floor(i / 3);
|
const row = Math.floor(i / 3);
|
||||||
const col = i % 3;
|
const col = i % 3;
|
||||||
const imageIndex = gridData.referenceGrid[i];
|
const imageIndex = gridData.referenceGrid[i];
|
||||||
const imageX = referenceGridX + col * cellSize + cellSize / 2 - 25; // 图片居中,假设图片大小50x50
|
const imageX = referenceGridX + col * cellSize + cellSize / 2 - 25;
|
||||||
const imageY = referenceGridY + row * cellSize + cellSize / 2 - 25;
|
const imageY = referenceGridY + row * cellSize + cellSize / 2 - 25;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -179,12 +178,11 @@ class PositionColoringDraw extends BaseDrawService {
|
|||||||
|
|
||||||
// 绘制网格线
|
// 绘制网格线
|
||||||
this.drawGridLines(
|
this.drawGridLines(
|
||||||
ctx,
|
|
||||||
taskGridX,
|
taskGridX,
|
||||||
taskGridY,
|
taskGridY,
|
||||||
taskGridWidth,
|
|
||||||
taskGridHeight,
|
|
||||||
taskGridSize,
|
taskGridSize,
|
||||||
|
taskGridSize,
|
||||||
|
gridSize,
|
||||||
gridSize,
|
gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -206,41 +204,6 @@ class PositionColoringDraw extends BaseDrawService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 绘制网格线
|
|
||||||
*/
|
|
||||||
private drawGridLines(
|
|
||||||
ctx: RenderingContext,
|
|
||||||
gridStartX: number,
|
|
||||||
gridStartY: number,
|
|
||||||
gridWidth: number,
|
|
||||||
gridHeight: number,
|
|
||||||
cellSize: number,
|
|
||||||
gridSize: number,
|
|
||||||
): void {
|
|
||||||
ctx.strokeStyle = '#000';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.setLineDash([]); // 实线
|
|
||||||
|
|
||||||
// 绘制垂直线
|
|
||||||
for (let i = 0; i <= gridSize; i++) {
|
|
||||||
const x = gridStartX + i * cellSize;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(x, gridStartY);
|
|
||||||
ctx.lineTo(x, gridStartY + gridHeight);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制水平线
|
|
||||||
for (let i = 0; i <= gridSize; i++) {
|
|
||||||
const y = gridStartY + i * cellSize;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(gridStartX, y);
|
|
||||||
ctx.lineTo(gridStartX + gridWidth, y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PositionColoringDraw;
|
export default PositionColoringDraw;
|
||||||
|
|||||||
@@ -84,9 +84,8 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
const margin = 40; // 左右边距
|
const margin = 40; // 左右边距
|
||||||
const legendCols = 4; // 图例列数
|
const legendCols = 4; // 图例列数
|
||||||
const legendRows = 2; // 图例行数
|
const legendRows = 2; // 图例行数
|
||||||
const cellSize = 65; // 每个格子的大小
|
const cellSize = 65; // 每个格子的宽度
|
||||||
const gridWidth = cellSize * legendCols;
|
const gridWidth = cellSize * legendCols;
|
||||||
const gridHeight = cellSize * legendRows;
|
|
||||||
|
|
||||||
// 绘制参考网格(上面的九宫格)
|
// 绘制参考网格(上面的九宫格)
|
||||||
const legendStartX =
|
const legendStartX =
|
||||||
@@ -95,11 +94,9 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
|
|
||||||
// 绘制参考网格的网格线
|
// 绘制参考网格的网格线
|
||||||
this.drawGridLines(
|
this.drawGridLines(
|
||||||
ctx,
|
|
||||||
legendStartX,
|
legendStartX,
|
||||||
legendStartY,
|
legendStartY,
|
||||||
gridWidth,
|
cellSize,
|
||||||
gridHeight,
|
|
||||||
cellSize,
|
cellSize,
|
||||||
legendCols,
|
legendCols,
|
||||||
legendRows,
|
legendRows,
|
||||||
@@ -113,7 +110,7 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
gridData.legendMapping.forEach((mapping, index: number) => {
|
gridData.legendMapping.forEach((mapping, index: number) => {
|
||||||
if (!mapping) return;
|
if (!mapping) return;
|
||||||
|
|
||||||
const shapeX = legendStartX + index * cellSize + cellSize / 2; // 图片居中,假设图片大小50x50
|
const shapeX = legendStartX + index * cellSize + cellSize / 2;
|
||||||
const shapeY = legendStartY + cellSize / 2;
|
const shapeY = legendStartY + cellSize / 2;
|
||||||
|
|
||||||
const shapeSize = 42;
|
const shapeSize = 42;
|
||||||
@@ -128,8 +125,8 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 第二行:绘制符号(使用 emoji)
|
// 第二行:绘制符号(使用 emoji)
|
||||||
const symbolX = legendStartX + index * cellSize + cellSize / 2; // 图片居中,假设图片大小50x50
|
const symbolX = legendStartX + index * cellSize + cellSize / 2;
|
||||||
const symbolY = legendStartY + cellSize + cellSize / 2 + 5;
|
const symbolY = legendStartY + cellSize + cellSize / 2;
|
||||||
this.drawSymbol(ctx, symbolX, symbolY, mapping.symbol, 30);
|
this.drawSymbol(ctx, symbolX, symbolY, mapping.symbol, 30);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -140,9 +137,8 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
const practiceStartY = dividerY + 30;
|
const practiceStartY = dividerY + 30;
|
||||||
const practiceCols = 8;
|
const practiceCols = 8;
|
||||||
const practiceRows = 8;
|
const practiceRows = 8;
|
||||||
const practiceCellSize = 60; // 练习格子大小(正方形)
|
const practiceCellSize = 60; // 练习格子宽度
|
||||||
const practiceGridWidth = practiceCellSize * practiceCols;
|
const practiceGridWidth = practiceCellSize * practiceCols;
|
||||||
const practiceGridHeight = practiceCellSize * practiceRows;
|
|
||||||
|
|
||||||
// 计算练习区域起始X位置(居中)
|
// 计算练习区域起始X位置(居中)
|
||||||
const practiceStartX =
|
const practiceStartX =
|
||||||
@@ -150,11 +146,9 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
|
|
||||||
// 绘制练习区域网格线(使用 drawGridLines)
|
// 绘制练习区域网格线(使用 drawGridLines)
|
||||||
this.drawGridLines(
|
this.drawGridLines(
|
||||||
ctx,
|
|
||||||
practiceStartX,
|
practiceStartX,
|
||||||
practiceStartY,
|
practiceStartY,
|
||||||
practiceGridWidth,
|
practiceCellSize,
|
||||||
practiceGridHeight,
|
|
||||||
practiceCellSize,
|
practiceCellSize,
|
||||||
practiceCols,
|
practiceCols,
|
||||||
practiceRows,
|
practiceRows,
|
||||||
@@ -195,71 +189,88 @@ class ShapeSymbolDraw extends BaseDrawService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制符号(使用 emoji 文字)
|
* 绘制符号(使用路径绘制,类似 shapeSymbolShapes.ts)
|
||||||
*/
|
*/
|
||||||
private drawSymbol(
|
private drawSymbol(
|
||||||
ctx: RenderingContext,
|
ctx: RenderingContext,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
symbol: string,
|
symbol: string,
|
||||||
fontSize: number,
|
size: number,
|
||||||
): void {
|
): void {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
ctx.translate(x, y);
|
||||||
|
|
||||||
// 符号映射:将符号转换为 emoji
|
const lineWidth = size * 0.15; // 线条宽度
|
||||||
const symbolMap: Record<string, string> = {
|
const halfSize = size / 2;
|
||||||
'+': '➕',
|
const strokeLength = halfSize * 0.7; // 线条长度
|
||||||
'-': '➖',
|
|
||||||
'×': '✖️',
|
|
||||||
'✓': '✔️',
|
|
||||||
};
|
|
||||||
|
|
||||||
const emojiSymbol = symbolMap[symbol] || symbol;
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = lineWidth;
|
||||||
|
ctx.lineCap = 'round';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
|
||||||
ctx.font = `bold ${fontSize}px Arial`;
|
switch (symbol) {
|
||||||
ctx.textAlign = 'center';
|
case '+':
|
||||||
ctx.textBaseline = 'middle';
|
// 加号:横线和竖线
|
||||||
ctx.fillStyle = '#000';
|
ctx.beginPath();
|
||||||
ctx.fillText(emojiSymbol, x, y);
|
// 横线
|
||||||
|
ctx.moveTo(-strokeLength, 0);
|
||||||
|
ctx.lineTo(strokeLength, 0);
|
||||||
|
// 竖线
|
||||||
|
ctx.moveTo(0, -strokeLength);
|
||||||
|
ctx.lineTo(0, strokeLength);
|
||||||
|
ctx.stroke();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
// 减号:横线
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(-strokeLength, 0);
|
||||||
|
ctx.lineTo(strokeLength, 0);
|
||||||
|
ctx.stroke();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '×':
|
||||||
|
// 乘号:两条斜线
|
||||||
|
ctx.beginPath();
|
||||||
|
// 左上到右下
|
||||||
|
ctx.moveTo(-strokeLength * 0.7, -strokeLength * 0.7);
|
||||||
|
ctx.lineTo(strokeLength * 0.7, strokeLength * 0.7);
|
||||||
|
// 右上到左下
|
||||||
|
ctx.moveTo(strokeLength * 0.7, -strokeLength * 0.7);
|
||||||
|
ctx.lineTo(-strokeLength * 0.7, strokeLength * 0.7);
|
||||||
|
ctx.stroke();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '✓':
|
||||||
|
// 对号:勾,整体更大,右侧的线更长
|
||||||
|
const checkScale = 1.2; // 对号整体放大1.2倍
|
||||||
|
ctx.beginPath();
|
||||||
|
const checkStartX = -strokeLength * 0.5 * checkScale;
|
||||||
|
const checkStartY = -strokeLength * 0.2 * checkScale;
|
||||||
|
const checkMidX = -strokeLength * 0.1 * checkScale;
|
||||||
|
const checkMidY = strokeLength * 0.3 * checkScale;
|
||||||
|
const checkEndX = strokeLength * 1.0 * checkScale; // 增加右侧长度
|
||||||
|
const checkEndY = -strokeLength * 0.4 * checkScale; // 稍微向上调整
|
||||||
|
ctx.moveTo(checkStartX, checkStartY);
|
||||||
|
ctx.lineTo(checkMidX, checkMidY);
|
||||||
|
ctx.lineTo(checkEndX, checkEndY);
|
||||||
|
ctx.stroke();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 默认绘制加号
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(-strokeLength, 0);
|
||||||
|
ctx.lineTo(strokeLength, 0);
|
||||||
|
ctx.moveTo(0, -strokeLength);
|
||||||
|
ctx.lineTo(0, strokeLength);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 绘制网格线
|
|
||||||
*/
|
|
||||||
private drawGridLines(
|
|
||||||
ctx: RenderingContext,
|
|
||||||
gridStartX: number,
|
|
||||||
gridStartY: number,
|
|
||||||
gridWidth: number,
|
|
||||||
gridHeight: number,
|
|
||||||
cellSize: number,
|
|
||||||
legendCols: number,
|
|
||||||
legendRows: number,
|
|
||||||
): void {
|
|
||||||
ctx.strokeStyle = '#000';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.setLineDash([]); // 实线
|
|
||||||
|
|
||||||
// 绘制垂直线
|
|
||||||
for (let i = 0; i <= legendCols; i++) {
|
|
||||||
const x = gridStartX + i * cellSize;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(x, gridStartY);
|
|
||||||
ctx.lineTo(x, gridStartY + gridHeight);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制水平线
|
|
||||||
for (let i = 0; i <= legendRows; i++) {
|
|
||||||
const y = gridStartY + i * cellSize;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(gridStartX, y);
|
|
||||||
ctx.lineTo(gridStartX + gridWidth, y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ShapeSymbolDraw;
|
export default ShapeSymbolDraw;
|
||||||
|
|||||||
@@ -17,12 +17,30 @@ export const SHAPE_SYMBOL_SHAPES: ShapeSymbolShape[] = [
|
|||||||
{ id: 'ellipse', name: '椭圆' },
|
{ id: 'ellipse', name: '椭圆' },
|
||||||
{ id: 'star', name: '五角星' },
|
{ id: 'star', name: '五角星' },
|
||||||
{ id: 'pentagon', name: '五边形' },
|
{ id: 'pentagon', name: '五边形' },
|
||||||
|
{ id: 'hexagon', name: '六边形' },
|
||||||
|
{ id: 'octagon', name: '八边形' },
|
||||||
|
{ id: 'cross', name: '十字形' },
|
||||||
|
{ id: 'rectangle', name: '长方形' },
|
||||||
|
{ id: 'sector', name: '扇形' },
|
||||||
{ id: 'heart', name: '心形' },
|
{ id: 'heart', name: '心形' },
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制图形(无边框,仅填充)
|
* 绘制图形选项
|
||||||
|
*/
|
||||||
|
export interface DrawShapeOptions {
|
||||||
|
/** 填充颜色,如果为 null 则不填充 */
|
||||||
|
fillColor?: string | null;
|
||||||
|
/** 边框颜色,如果为 null 则不绘制边框 */
|
||||||
|
strokeColor?: string | null;
|
||||||
|
/** 边框宽度,默认为 1.5 */
|
||||||
|
strokeWidth?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制图形(支持边框和填充控制)
|
||||||
* 所有图形保持相同的大小
|
* 所有图形保持相同的大小
|
||||||
|
* @overload 旧的方式:drawShapeSymbolShape(ctx, shapeId, x, y, size, fillColor)
|
||||||
*/
|
*/
|
||||||
export function drawShapeSymbolShape(
|
export function drawShapeSymbolShape(
|
||||||
ctx: RenderingContext,
|
ctx: RenderingContext,
|
||||||
@@ -31,32 +49,110 @@ export function drawShapeSymbolShape(
|
|||||||
y: number,
|
y: number,
|
||||||
size: number,
|
size: number,
|
||||||
fillColor: string,
|
fillColor: string,
|
||||||
|
options?: DrawShapeOptions,
|
||||||
|
): void;
|
||||||
|
/**
|
||||||
|
* 绘制图形(支持边框和填充控制)
|
||||||
|
* 所有图形保持相同的大小
|
||||||
|
* @overload 新的方式:drawShapeSymbolShape(ctx, shapeId, x, y, size, options)
|
||||||
|
*/
|
||||||
|
export function drawShapeSymbolShape(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
shapeId: string,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
options: DrawShapeOptions,
|
||||||
|
): void;
|
||||||
|
/**
|
||||||
|
* 绘制图形(支持边框和填充控制)
|
||||||
|
* 所有图形保持相同的大小
|
||||||
|
*/
|
||||||
|
export function drawShapeSymbolShape(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
shapeId: string,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
fillColorOrOptions: string | DrawShapeOptions,
|
||||||
|
options?: DrawShapeOptions,
|
||||||
): void {
|
): void {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(x, y);
|
ctx.translate(x, y);
|
||||||
|
|
||||||
const radius = size / 2;
|
const radius = size / 2;
|
||||||
|
|
||||||
ctx.fillStyle = fillColor;
|
// 兼容旧的调用方式:drawShapeSymbolShape(ctx, shapeId, x, y, size, fillColor)
|
||||||
|
let fillColor: string | null = null;
|
||||||
|
let drawOptions: DrawShapeOptions = {};
|
||||||
|
|
||||||
|
if (typeof fillColorOrOptions === 'string') {
|
||||||
|
// 旧的方式:fillColor 是字符串
|
||||||
|
fillColor = fillColorOrOptions;
|
||||||
|
drawOptions = options || {};
|
||||||
|
} else {
|
||||||
|
// 新的方式:第一个参数是 options
|
||||||
|
drawOptions = fillColorOrOptions || {};
|
||||||
|
fillColor = drawOptions.fillColor || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置填充和描边样式
|
||||||
|
if (fillColor) {
|
||||||
|
ctx.fillStyle = fillColor;
|
||||||
|
}
|
||||||
|
if (drawOptions.strokeColor) {
|
||||||
|
ctx.strokeStyle = drawOptions.strokeColor;
|
||||||
|
ctx.lineWidth = drawOptions.strokeWidth || 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一的填充和描边处理函数
|
||||||
|
const drawPath = () => {
|
||||||
|
if (fillColor) {
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (drawOptions.strokeColor) {
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
switch (shapeId) {
|
switch (shapeId) {
|
||||||
case 'circle':
|
case 'circle':
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(0, 0, radius, 0, Math.PI * 2);
|
ctx.arc(0, 0, radius, 0, Math.PI * 2);
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'square':
|
case 'square':
|
||||||
ctx.fillRect(-radius, -radius, size, size);
|
// 正方形缩小为原来的0.9倍
|
||||||
|
const squareSize = size * 0.9;
|
||||||
|
const squareRadius = squareSize / 2;
|
||||||
|
if (fillColor) {
|
||||||
|
ctx.fillRect(
|
||||||
|
-squareRadius,
|
||||||
|
-squareRadius,
|
||||||
|
squareSize,
|
||||||
|
squareSize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (drawOptions.strokeColor) {
|
||||||
|
ctx.strokeRect(
|
||||||
|
-squareRadius,
|
||||||
|
-squareRadius,
|
||||||
|
squareSize,
|
||||||
|
squareSize,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'triangle':
|
case 'triangle':
|
||||||
|
// 三角形缩小为原来的0.9倍
|
||||||
|
const triangleRadius = radius * 0.9;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(0, -radius);
|
ctx.moveTo(0, -triangleRadius);
|
||||||
ctx.lineTo(-radius, radius);
|
ctx.lineTo(-triangleRadius, triangleRadius);
|
||||||
ctx.lineTo(radius, radius);
|
ctx.lineTo(triangleRadius, triangleRadius);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'diamond':
|
case 'diamond':
|
||||||
@@ -66,7 +162,7 @@ export function drawShapeSymbolShape(
|
|||||||
ctx.lineTo(0, radius);
|
ctx.lineTo(0, radius);
|
||||||
ctx.lineTo(-radius, 0);
|
ctx.lineTo(-radius, 0);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'trapezoid':
|
case 'trapezoid':
|
||||||
@@ -77,13 +173,13 @@ export function drawShapeSymbolShape(
|
|||||||
ctx.lineTo(radius, radius * 0.7);
|
ctx.lineTo(radius, radius * 0.7);
|
||||||
ctx.lineTo(-radius, radius * 0.7);
|
ctx.lineTo(-radius, radius * 0.7);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'ellipse':
|
case 'ellipse':
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.ellipse(0, 0, radius * 0.8, radius * 0.6, 0, 0, Math.PI * 2);
|
ctx.ellipse(0, 0, radius * 0.8, radius * 0.6, 0, 0, Math.PI * 2);
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'star':
|
case 'star':
|
||||||
@@ -106,7 +202,7 @@ export function drawShapeSymbolShape(
|
|||||||
ctx.lineTo(x2, y2);
|
ctx.lineTo(x2, y2);
|
||||||
}
|
}
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'pentagon':
|
case 'pentagon':
|
||||||
@@ -119,7 +215,94 @@ export function drawShapeSymbolShape(
|
|||||||
else ctx.lineTo(px, py);
|
else ctx.lineTo(px, py);
|
||||||
}
|
}
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'hexagon':
|
||||||
|
// 六边形
|
||||||
|
ctx.beginPath();
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
const angle = (i * 2 * Math.PI) / 6 - Math.PI / 2;
|
||||||
|
const px = Math.cos(angle) * radius;
|
||||||
|
const py = Math.sin(angle) * radius;
|
||||||
|
if (i === 0) ctx.moveTo(px, py);
|
||||||
|
else ctx.lineTo(px, py);
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
|
drawPath();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'octagon':
|
||||||
|
// 八边形
|
||||||
|
ctx.beginPath();
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const angle = (i * 2 * Math.PI) / 8 - Math.PI / 2;
|
||||||
|
const px = Math.cos(angle) * radius;
|
||||||
|
const py = Math.sin(angle) * radius;
|
||||||
|
if (i === 0) ctx.moveTo(px, py);
|
||||||
|
else ctx.lineTo(px, py);
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
|
drawPath();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'cross':
|
||||||
|
// 十字形
|
||||||
|
const crossWidth = radius * 0.3; // 十字的宽度
|
||||||
|
if (fillColor) {
|
||||||
|
// 竖条
|
||||||
|
ctx.fillRect(-crossWidth, -radius, crossWidth * 2, size);
|
||||||
|
// 横条
|
||||||
|
ctx.fillRect(-radius, -crossWidth, size, crossWidth * 2);
|
||||||
|
}
|
||||||
|
if (drawOptions.strokeColor) {
|
||||||
|
// 竖条
|
||||||
|
ctx.strokeRect(-crossWidth, -radius, crossWidth * 2, size);
|
||||||
|
// 横条
|
||||||
|
ctx.strokeRect(-radius, -crossWidth, size, crossWidth * 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'rectangle':
|
||||||
|
// 长方形(横向,宽度是高度的1.2倍)
|
||||||
|
const rectWidth = radius * 1.1;
|
||||||
|
const rectHeight = radius * 0.7;
|
||||||
|
if (fillColor) {
|
||||||
|
ctx.fillRect(
|
||||||
|
-rectWidth,
|
||||||
|
-rectHeight,
|
||||||
|
rectWidth * 2,
|
||||||
|
rectHeight * 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (drawOptions.strokeColor) {
|
||||||
|
ctx.strokeRect(
|
||||||
|
-rectWidth,
|
||||||
|
-rectHeight,
|
||||||
|
rectWidth * 2,
|
||||||
|
rectHeight * 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 扇形
|
||||||
|
case 'sector':
|
||||||
|
// 扇形(90度扇形),圆心在格子中心点偏左二分之一的位置
|
||||||
|
const sectorCenterX = -radius / 2; // 向左偏移半径的一半
|
||||||
|
const sectorCenterY = 0;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(sectorCenterX, sectorCenterY);
|
||||||
|
ctx.arc(
|
||||||
|
sectorCenterX,
|
||||||
|
sectorCenterY,
|
||||||
|
radius,
|
||||||
|
-Math.PI / 4,
|
||||||
|
Math.PI / 4,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
ctx.lineTo(sectorCenterX, sectorCenterY);
|
||||||
|
ctx.closePath();
|
||||||
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'heart':
|
case 'heart':
|
||||||
@@ -141,14 +324,14 @@ export function drawShapeSymbolShape(
|
|||||||
ctx.bezierCurveTo(tx(50), ty(80), tx(70), ty(65), tx(75), ty(50));
|
ctx.bezierCurveTo(tx(50), ty(80), tx(70), ty(65), tx(75), ty(50));
|
||||||
ctx.bezierCurveTo(tx(80), ty(35), tx(65), ty(20), tx(50), ty(35));
|
ctx.bezierCurveTo(tx(80), ty(35), tx(65), ty(20), tx(50), ty(35));
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
drawPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// 默认绘制圆形
|
// 默认绘制圆形
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(0, 0, radius, 0, Math.PI * 2);
|
ctx.arc(0, 0, radius, 0, Math.PI * 2);
|
||||||
ctx.fill();
|
drawPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|||||||
@@ -171,4 +171,50 @@ export class BaseDrawService {
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.setLineDash([]); // 重置为实线
|
ctx.setLineDash([]); // 重置为实线
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制网格线(逻辑像素,尺寸除以3)
|
||||||
|
* @param gridStartX 网格起始X坐标
|
||||||
|
* @param gridStartY 网格起始Y坐标
|
||||||
|
* @param cellWidth 每个格子的宽度
|
||||||
|
* @param cellHeight 每个格子的高度
|
||||||
|
* @param cols 列数
|
||||||
|
* @param rows 行数
|
||||||
|
*/
|
||||||
|
drawGridLines(
|
||||||
|
gridStartX: number,
|
||||||
|
gridStartY: number,
|
||||||
|
cellWidth: number,
|
||||||
|
cellHeight: number,
|
||||||
|
cols: number,
|
||||||
|
rows: number,
|
||||||
|
): void {
|
||||||
|
const { ctx } = this;
|
||||||
|
|
||||||
|
// 在函数内部计算网格总宽度和高度
|
||||||
|
const gridWidth = cellWidth * cols;
|
||||||
|
const gridHeight = cellHeight * rows;
|
||||||
|
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.setLineDash([]); // 实线
|
||||||
|
|
||||||
|
// 绘制垂直线
|
||||||
|
for (let i = 0; i <= cols; i++) {
|
||||||
|
const x = gridStartX + i * cellWidth;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, gridStartY);
|
||||||
|
ctx.lineTo(x, gridStartY + gridHeight);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制水平线
|
||||||
|
for (let i = 0; i <= rows; i++) {
|
||||||
|
const y = gridStartY + i * cellHeight;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(gridStartX, y);
|
||||||
|
ctx.lineTo(gridStartX + gridWidth, y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,19 @@
|
|||||||
"condition": {
|
"condition": {
|
||||||
"miniprogram": {
|
"miniprogram": {
|
||||||
"list": [
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "focusPages/colorPattern/colorPattern",
|
||||||
|
"pathName": "focusPages/colorPattern/colorPattern",
|
||||||
|
"query": "id=color-pattern",
|
||||||
|
"scene": null,
|
||||||
|
"launchMode": "default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "focusPages/shapeSymbol/shapeSymbol",
|
"name": "focusPages/shapeSymbol/shapeSymbol",
|
||||||
"pathName": "focusPages/shapeSymbol/shapeSymbol",
|
"pathName": "focusPages/shapeSymbol/shapeSymbol",
|
||||||
"query": "id=shape-symbol",
|
"query": "id=shape-symbol",
|
||||||
"scene": null,
|
"launchMode": "default",
|
||||||
"launchMode": "default"
|
"scene": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focusPages/positionColoring/positionColoring",
|
"name": "focusPages/positionColoring/positionColoring",
|
||||||
|
|||||||
Reference in New Issue
Block a user