const util = require('../../utils/util') Component({ properties: { duration: { type: Number, value: 60 }, remaining: { type: Number, value: 60 }, size: { type: Number, value: 280 }, ringWidth: { type: Number, value: 14 }, status: { type: String, value: 'idle' }, primaryColor: { type: String, value: '#FF6B35' }, primaryLightColor: { type: String, value: '#FF8C5A' } }, data: { displayTime: '00:00', statusText: '准备开始' }, observers: { 'remaining, status, duration, size, ringWidth, primaryColor'() { const texts = { idle: '准备开始', running: '坚持住', paused: '已暂停', completed: '完成!' } this.setData({ displayTime: util.formatTime(this.data.remaining), statusText: texts[this.data.status] || '' }) this._draw() } }, lifetimes: { ready() { const query = this.createSelectorQuery() query.select('#ringCanvas') .fields({ node: true, size: true }) .exec((res) => { if (!res || !res[0] || !res[0].node) return const canvas = res[0].node const dpr = wx.getSystemInfoSync().pixelRatio || 2 const displaySize = this.data.size canvas.width = displaySize * dpr canvas.height = displaySize * dpr this._ctx = canvas.getContext('2d') this._dpr = dpr this._draw() }) } }, methods: { _draw() { const ctx = this._ctx if (!ctx) return const { size, ringWidth, duration, remaining, primaryColor } = this.data const dpr = this._dpr const w = size * dpr const h = size * dpr ctx.clearRect(0, 0, w, h) const cx = w / 2 const cy = h / 2 const radius = (size - ringWidth) / 2 * dpr const lw = ringWidth * dpr // track ring ctx.beginPath() ctx.arc(cx, cy, radius, 0, Math.PI * 2) ctx.strokeStyle = '#EEEEEE' ctx.lineWidth = lw ctx.lineCap = 'round' ctx.stroke() // progress arc (clockwise from 12 o'clock) const ratio = duration > 0 ? Math.max(0, Math.min(1, remaining / duration)) : 0 if (ratio > 0.001) { const startAngle = -Math.PI / 2 const endAngle = startAngle + ratio * Math.PI * 2 ctx.beginPath() ctx.arc(cx, cy, radius, startAngle, endAngle) ctx.strokeStyle = primaryColor ctx.lineWidth = lw ctx.lineCap = 'round' ctx.stroke() } } } })