Files
perler-beads-applet/src/components/PatternCanvas.vue
T

37 lines
2.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed,getCurrentInstance,nextTick,onMounted,watch } from 'vue'
import { cellAtPoint } from '../core/canvas'
import type { Pattern } from '../core/types'
let props=withDefaults(defineProps<{pattern:Pattern;size?:number;highlight?:string;grid?:boolean;completed?:number[]}>(),{size:160,highlight:'',grid:false,completed:()=>[]})
let emit=defineEmits<{cell:[index:number]}>()
let instance=getCurrentInstance(); let id='p'+instance?.uid
let height=computed(()=>Math.round(props.size*props.pattern.height/props.pattern.width))
async function draw(){await nextTick(); let p=props.pattern;let ctx=uni.createCanvasContext(id,instance);let s=props.size/p.width
ctx.clearRect(0,0,props.size,height.value);ctx.setFillStyle('#f0efe5');ctx.fillRect(0,0,props.size,height.value)
let palette=new Map(p.colors.map(c=>[c.code,c.hex]));let done=new Set(props.completed)
p.cells.forEach((c,i)=>{if(!c)return;ctx.setGlobalAlpha(props.highlight&&c!==props.highlight? .15:1);ctx.setFillStyle(palette.get(c)||'#777');let x=i%p.width*s,y=Math.floor(i/p.width)*s;ctx.fillRect(x,y,s,s);ctx.setGlobalAlpha(1)
if(props.grid&&s>=24){ctx.setFillStyle('#fff');ctx.fillRect(x+1,y+1,s-2,11);ctx.setFillStyle('#253d32');ctx.setFontSize(8);ctx.fillText(c,x+2,y+9)}
if(done.has(i)){ctx.setFillStyle('rgba(255,255,255,0.67)');ctx.fillRect(x,y,s,s);ctx.setFillStyle('#265b49');ctx.setFontSize(Math.max(9,s*.6));ctx.fillText('✓',x+s*.15,y+s*.8)}
});
if(props.grid){
ctx.setStrokeStyle('rgba(100,119,98,0.24)');ctx.setLineWidth(.5);ctx.beginPath()
for(let column=0;column<=p.width;column++){ctx.moveTo(column*s,0);ctx.lineTo(column*s,height.value)}
for(let row=0;row<=p.height;row++){ctx.moveTo(0,row*s);ctx.lineTo(props.size,row*s)}
ctx.stroke()
}
ctx.draw()
}
function tap(e:any){
let touch=e.changedTouches?.[0]||e.touches?.[0]
let x=touch?.clientX??e.detail?.x,y=touch?.clientY??e.detail?.y
// 事件坐标属于视口,必须扣除画布在滚动容器中的实际偏移。
uni.createSelectorQuery().in(instance?.proxy).select('#'+id).boundingClientRect((value:any)=>{
if(!value)return
let cell=cellAtPoint(x,y,value,props.pattern.width,props.pattern.height)
if(cell!==null)emit('cell',cell)
}).exec()
}
onMounted(draw);watch(()=>[props.pattern,props.size,props.highlight,props.completed],draw,{deep:true})
</script>
<template><canvas :id="id" :canvas-id="id" :style="{width:size+'px',height:height+'px'}" :aria-label="pattern.title+','+pattern.width+'乘'+pattern.height+'格'" @tap="tap" /></template>