diff --git a/miniprogram/app.json b/miniprogram/app.json index 58f45e0..cd7f162 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -28,7 +28,8 @@ "gridDrawing/gridDrawing", "shape/shape", "positionColoring/positionColoring", - "shapeSymbol/shapeSymbol" + "shapeSymbol/shapeSymbol", + "colorPattern/colorPattern" ], "independent": false } diff --git a/miniprogram/app.ts b/miniprogram/app.ts index 1cb3727..818bc87 100644 --- a/miniprogram/app.ts +++ b/miniprogram/app.ts @@ -25,8 +25,6 @@ App({ if (env !== 'release') { const printConfig = wx.getStorageSync('printConfig') || defaultPrintConfig; - // 开发环境,设置为 LogoImage - printConfig.header = 'LogoImage'; this.globalData.printConfig = printConfig; } }, diff --git a/miniprogram/constants/focusFunctions.ts b/miniprogram/constants/focusFunctions.ts index 8a5435a..16a5b6d 100644 --- a/miniprogram/constants/focusFunctions.ts +++ b/miniprogram/constants/focusFunctions.ts @@ -32,6 +32,14 @@ export const FOCUS_FUNCTION_TYPES: FocusFunctionType[] = [ desc: '观察卡片位置,在对应的方格中涂上颜色', icon: '📍', }, + // 颜色找规律 + { + id: 'color-pattern', + page: 'colorPattern', + title: '颜色找规律', + desc: '观察颜色规律,在空白图形中涂上颜色', + icon: '🎨', + }, // 格子仿画 { id: 'grid-drawing-3x3', diff --git a/miniprogram/focusPages/colorPattern/colorPattern.json b/miniprogram/focusPages/colorPattern/colorPattern.json new file mode 100644 index 0000000..7560b48 --- /dev/null +++ b/miniprogram/focusPages/colorPattern/colorPattern.json @@ -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" + } +} diff --git a/miniprogram/focusPages/colorPattern/colorPattern.ts b/miniprogram/focusPages/colorPattern/colorPattern.ts new file mode 100644 index 0000000..90d2c1f --- /dev/null +++ b/miniprogram/focusPages/colorPattern/colorPattern.ts @@ -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, + ) => { + 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; // 前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 = new Array(6).fill(null); + + groups.push({ + shapeId: selectedShape.id, + colors: [...patternColors, ...emptyColors], + }); + } + + this.gridData = { + groups, + }; + + this.drawCanvas(); + }, +}); diff --git a/miniprogram/focusPages/colorPattern/colorPattern.wxml b/miniprogram/focusPages/colorPattern/colorPattern.wxml new file mode 100644 index 0000000..5d3cbdb --- /dev/null +++ b/miniprogram/focusPages/colorPattern/colorPattern.wxml @@ -0,0 +1,37 @@ + + + 预览打印效果 + + + + + + + + + + 随机生成 + + + + + + + diff --git a/miniprogram/focusPages/colorPattern/colorPattern.wxss b/miniprogram/focusPages/colorPattern/colorPattern.wxss new file mode 100644 index 0000000..ddc41cc --- /dev/null +++ b/miniprogram/focusPages/colorPattern/colorPattern.wxss @@ -0,0 +1 @@ +@import '../../base/baseDrawPage.wxss'; diff --git a/miniprogram/focusPages/shared/service/colorPatternDraw.ts b/miniprogram/focusPages/shared/service/colorPatternDraw.ts new file mode 100644 index 0000000..270a346 --- /dev/null +++ b/miniprogram/focusPages/shared/service/colorPatternDraw.ts @@ -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; // 长度为10,前4个有颜色,后6个为null + }>; +} + +/** + * 颜色找规律绘制服务 + */ +class ColorPatternDraw extends BaseDrawService { + gridData: ColorPatternData | null = null; + + constructor( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) { + 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; diff --git a/miniprogram/focusPages/shared/service/positionColoringDraw.ts b/miniprogram/focusPages/shared/service/positionColoringDraw.ts index 6d26bb3..e0f50f3 100644 --- a/miniprogram/focusPages/shared/service/positionColoringDraw.ts +++ b/miniprogram/focusPages/shared/service/positionColoringDraw.ts @@ -80,7 +80,7 @@ class PositionColoringDraw extends BaseDrawService { const margin = 40; // 左右边距 const gridSize = 3; // 3x3网格 - const cellSize = 65; // 每个格子的大小 + const cellSize = 65; // 每个格子的宽度 const gridWidth = cellSize * gridSize; const gridHeight = cellSize * gridSize; @@ -91,12 +91,11 @@ class PositionColoringDraw extends BaseDrawService { // 绘制参考网格的网格线 this.drawGridLines( - ctx, referenceGridX, referenceGridY, - gridWidth, - gridHeight, cellSize, + cellSize, + gridSize, gridSize, ); @@ -105,7 +104,7 @@ class PositionColoringDraw extends BaseDrawService { const row = Math.floor(i / 3); const col = i % 3; 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; try { @@ -179,12 +178,11 @@ class PositionColoringDraw extends BaseDrawService { // 绘制网格线 this.drawGridLines( - ctx, taskGridX, taskGridY, - taskGridWidth, - taskGridHeight, taskGridSize, + taskGridSize, + 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; diff --git a/miniprogram/focusPages/shared/service/shapeSymbolDraw.ts b/miniprogram/focusPages/shared/service/shapeSymbolDraw.ts index b9fb4d3..f6a828d 100644 --- a/miniprogram/focusPages/shared/service/shapeSymbolDraw.ts +++ b/miniprogram/focusPages/shared/service/shapeSymbolDraw.ts @@ -84,9 +84,8 @@ class ShapeSymbolDraw extends BaseDrawService { const margin = 40; // 左右边距 const legendCols = 4; // 图例列数 const legendRows = 2; // 图例行数 - const cellSize = 65; // 每个格子的大小 + const cellSize = 65; // 每个格子的宽度 const gridWidth = cellSize * legendCols; - const gridHeight = cellSize * legendRows; // 绘制参考网格(上面的九宫格) const legendStartX = @@ -95,11 +94,9 @@ class ShapeSymbolDraw extends BaseDrawService { // 绘制参考网格的网格线 this.drawGridLines( - ctx, legendStartX, legendStartY, - gridWidth, - gridHeight, + cellSize, cellSize, legendCols, legendRows, @@ -113,7 +110,7 @@ class ShapeSymbolDraw extends BaseDrawService { gridData.legendMapping.forEach((mapping, index: number) => { if (!mapping) return; - const shapeX = legendStartX + index * cellSize + cellSize / 2; // 图片居中,假设图片大小50x50 + const shapeX = legendStartX + index * cellSize + cellSize / 2; const shapeY = legendStartY + cellSize / 2; const shapeSize = 42; @@ -128,8 +125,8 @@ class ShapeSymbolDraw extends BaseDrawService { ); // 第二行:绘制符号(使用 emoji) - const symbolX = legendStartX + index * cellSize + cellSize / 2; // 图片居中,假设图片大小50x50 - const symbolY = legendStartY + cellSize + cellSize / 2 + 5; + const symbolX = legendStartX + index * cellSize + cellSize / 2; + const symbolY = legendStartY + cellSize + cellSize / 2; this.drawSymbol(ctx, symbolX, symbolY, mapping.symbol, 30); }); @@ -140,9 +137,8 @@ class ShapeSymbolDraw extends BaseDrawService { const practiceStartY = dividerY + 30; const practiceCols = 8; const practiceRows = 8; - const practiceCellSize = 60; // 练习格子大小(正方形) + const practiceCellSize = 60; // 练习格子宽度 const practiceGridWidth = practiceCellSize * practiceCols; - const practiceGridHeight = practiceCellSize * practiceRows; // 计算练习区域起始X位置(居中) const practiceStartX = @@ -150,11 +146,9 @@ class ShapeSymbolDraw extends BaseDrawService { // 绘制练习区域网格线(使用 drawGridLines) this.drawGridLines( - ctx, practiceStartX, practiceStartY, - practiceGridWidth, - practiceGridHeight, + practiceCellSize, practiceCellSize, practiceCols, practiceRows, @@ -195,71 +189,88 @@ class ShapeSymbolDraw extends BaseDrawService { } /** - * 绘制符号(使用 emoji 文字) + * 绘制符号(使用路径绘制,类似 shapeSymbolShapes.ts) */ private drawSymbol( ctx: RenderingContext, x: number, y: number, symbol: string, - fontSize: number, + size: number, ): void { ctx.save(); + ctx.translate(x, y); - // 符号映射:将符号转换为 emoji - const symbolMap: Record = { - '+': '➕', - '-': '➖', - '×': '✖️', - '✓': '✔️', - }; + const lineWidth = size * 0.15; // 线条宽度 + 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`; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = '#000'; - ctx.fillText(emojiSymbol, x, y); + switch (symbol) { + case '+': + // 加号:横线和竖线 + ctx.beginPath(); + // 横线 + 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(); } - - /** - * 绘制网格线 - */ - 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; diff --git a/miniprogram/focusPages/shared/shapes/shapeSymbolShapes.ts b/miniprogram/focusPages/shared/shapes/shapeSymbolShapes.ts index b89836a..d72aa41 100644 --- a/miniprogram/focusPages/shared/shapes/shapeSymbolShapes.ts +++ b/miniprogram/focusPages/shared/shapes/shapeSymbolShapes.ts @@ -17,12 +17,30 @@ export const SHAPE_SYMBOL_SHAPES: ShapeSymbolShape[] = [ { id: 'ellipse', name: '椭圆' }, { id: 'star', name: '五角星' }, { id: 'pentagon', name: '五边形' }, + { id: 'hexagon', name: '六边形' }, + { id: 'octagon', name: '八边形' }, + { id: 'cross', name: '十字形' }, + { id: 'rectangle', name: '长方形' }, + { id: 'sector', 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( ctx: RenderingContext, @@ -31,32 +49,110 @@ export function drawShapeSymbolShape( y: number, size: number, 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 { ctx.save(); ctx.translate(x, y); 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) { case 'circle': ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); - ctx.fill(); + drawPath(); break; 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; case 'triangle': + // 三角形缩小为原来的0.9倍 + const triangleRadius = radius * 0.9; ctx.beginPath(); - ctx.moveTo(0, -radius); - ctx.lineTo(-radius, radius); - ctx.lineTo(radius, radius); + ctx.moveTo(0, -triangleRadius); + ctx.lineTo(-triangleRadius, triangleRadius); + ctx.lineTo(triangleRadius, triangleRadius); ctx.closePath(); - ctx.fill(); + drawPath(); break; case 'diamond': @@ -66,7 +162,7 @@ export function drawShapeSymbolShape( ctx.lineTo(0, radius); ctx.lineTo(-radius, 0); ctx.closePath(); - ctx.fill(); + drawPath(); break; case 'trapezoid': @@ -77,13 +173,13 @@ export function drawShapeSymbolShape( ctx.lineTo(radius, radius * 0.7); ctx.lineTo(-radius, radius * 0.7); ctx.closePath(); - ctx.fill(); + drawPath(); break; case 'ellipse': ctx.beginPath(); ctx.ellipse(0, 0, radius * 0.8, radius * 0.6, 0, 0, Math.PI * 2); - ctx.fill(); + drawPath(); break; case 'star': @@ -106,7 +202,7 @@ export function drawShapeSymbolShape( ctx.lineTo(x2, y2); } ctx.closePath(); - ctx.fill(); + drawPath(); break; case 'pentagon': @@ -119,7 +215,94 @@ export function drawShapeSymbolShape( else ctx.lineTo(px, py); } 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; 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(80), ty(35), tx(65), ty(20), tx(50), ty(35)); ctx.closePath(); - ctx.fill(); + drawPath(); break; default: // 默认绘制圆形 ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); - ctx.fill(); + drawPath(); } ctx.restore(); diff --git a/miniprogram/service/baseDraw.ts b/miniprogram/service/baseDraw.ts index d8c5b81..df20a00 100644 --- a/miniprogram/service/baseDraw.ts +++ b/miniprogram/service/baseDraw.ts @@ -171,4 +171,50 @@ export class BaseDrawService { ctx.stroke(); 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(); + } + } } diff --git a/project.private.config.json b/project.private.config.json index 2d5af9b..748ecf1 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -23,12 +23,19 @@ "condition": { "miniprogram": { "list": [ + { + "name": "focusPages/colorPattern/colorPattern", + "pathName": "focusPages/colorPattern/colorPattern", + "query": "id=color-pattern", + "scene": null, + "launchMode": "default" + }, { "name": "focusPages/shapeSymbol/shapeSymbol", "pathName": "focusPages/shapeSymbol/shapeSymbol", "query": "id=shape-symbol", - "scene": null, - "launchMode": "default" + "launchMode": "default", + "scene": null }, { "name": "focusPages/positionColoring/positionColoring",