Skip to content

ICanvas - 运动手环

演示

在线预览
在线模拟尺寸:

介绍

这是一个常见的手环旋转动画,主要学习点是演示如何让元素循环播放动画,以及控制进度点,数字之间的更新和转换。

示例源码

uvue
vue
<template>

	<!-- #ifdef MP-WEIXIN -->
	<page-meta :page-style="`background-color:${xThemeConfigBgColor}`">
		<navigation-bar :background-color="xThemeConfigNavBgColor"
			:front-color="xThemeConfigNavFontColor"></navigation-bar>
	</page-meta>
	<!-- #endif -->

	<x-sheet>
		<x-text font-size="18" class=" text-weight-b mb-8">运动环示例</x-text>
		<x-text color="#999999" class="mb-8">请结合自己的物联网设备调整和绘制</x-text>

	</x-sheet>
	<x-sheet color="#000" dark-color="#000" :padding="['0']">
		<canvas :id="canvasId" 
			android-layer-type="hardware" 
			@click="bindEvents" 
			@touchstart="bindEvents" 
			@touchmove="bindEvents"
			@touchend="bindEvents" 
			@touchcancel="bindEvents" 
			@mousedown="bindEvents" 
			@mousemove="bindEvents"
			@mouseup="bindEvents"
			 
			<!-- #ifdef WEB -->
			@mouseleave="bindEvents"
			<!-- #endif -->
			style="width: 100%;height: 450px;" ref="canvasDom"
			>
		</canvas>
	</x-sheet>


</template>

<script setup>
	import { ICanvas } from '@/uni_modules/tmx-ui/core/canvas/ICanvas.uts';
	import { CanvasEventType, ICanvasEvent } from '@/uni_modules/tmx-ui/core/canvas/interface.uts';

	import { IRect } from '@/uni_modules/tmx-ui/core/canvas/lib/rect.uts';
	import { IText } from '@/uni_modules/tmx-ui/core/canvas/lib/text.uts';
	import { Tween } from '@/uni_modules/tmx-ui/core/canvas/lib/animation/tween.uts';
	import { ImageShape } from '@/uni_modules/tmx-ui/core/canvas/lib/image.uts';
	import { Path2DShape } from '@/uni_modules/tmx-ui/core/canvas/lib/path2d.uts';
	import { IRing } from '@/uni_modules/tmx-ui/core/canvas/lib/ring.uts';
	import { IArc } from '@/uni_modules/tmx-ui/core/canvas/lib/arc.uts';
	import { ISector } from '@/uni_modules/tmx-ui/core/canvas/lib/sector.uts';
	import { IRegularPolygon } from '@/uni_modules/tmx-ui/core/canvas/lib/regularPolygon.uts';
	import { ILinePolygon } from '@/uni_modules/tmx-ui/core/canvas/lib/linePolygon.uts';
	import { ICircle } from '@/uni_modules/tmx-ui/core/canvas/lib/circle.uts';
	import { IEllipse } from '@/uni_modules/tmx-ui/core/canvas/lib/ellipse.uts';
	import { IStar } from '@/uni_modules/tmx-ui/core/canvas/lib/star.uts';
	import { ILine } from '@/uni_modules/tmx-ui/core/canvas/lib/line.uts';



	const canvasDom = ref<UniCanvasElement | null>(null)
	const canvasId = "xCanvas-" + Math.random().toString(16).substring(4)
	const proxy = getCurrentInstance()?.proxy ?? null;
	const xcanvas = ref<ICanvas>(new ICanvas({ canvasId: canvasId, component: proxy as any | null }));
	let tw1 = null as Tween | null
	let tw2 = null as Tween | null
	let tw3 = null as Tween | null
	let tw4 = null as Tween | null

	const bindEvents = (evt : UniTouchEvent | UniPointerEvent | UniMouseEvent) => {
		xcanvas.value.bindEvent(evt)
	}


	// 绘制刻度
	const drawerRule = () => {
		if (xcanvas.value == null) return;
		const render = xcanvas.value! as ICanvas
		let centerX = render.boxWidth / 2
		let centerY = render.boxHeight / 2
		let radius = 65
		// 首先定义刻度的参数
		const divisions = 45; // 等分数量
		const tickLength = 10; // 刻度长度
		const innerRadius = radius - tickLength; // 内径半径(从这里开始向外画刻度)
		// 计算起始角度和结束角度(转换为数学角度)
		const startAngle = 135;
		const endAngle = 45;
		// 处理角度范围(确保endAngle大于startAngle)
		const totalAngle = endAngle <= startAngle ? endAngle + 360 - startAngle : endAngle - startAngle;
		// 计算每个刻度之间的角度
		const angleStep = totalAngle / divisions;
		// 绘制刻度
		for (let i = 0; i <= divisions; i++) {
			// 当前刻度的角度
			const currentAngle = (startAngle + i * angleStep) * (Math.PI / 180);
	
			// 计算刻度起点(内径上的点)
			const innerX = centerX + innerRadius * Math.cos(currentAngle);
			const innerY = centerY + innerRadius * Math.sin(currentAngle);
	
			// 计算刻度终点(外径上的点)
			const outerX = centerX + radius * Math.cos(currentAngle);
			const outerY = centerY + radius * Math.sin(currentAngle);
	
			// 创建刻度线
			const tick = new ILine({
				pointStart: { x: innerX, y: innerY },
				pointEnd: { x: outerX, y: outerY },
				stroke: "#831f55",
				strokeWidth: 1,
				lineCap:'round'
			}, render);
	
			// 添加到画布
			render.addShape(tick);
		}
	}
	

	const drawer = () => {
		if (xcanvas.value == null) return;
		const render = xcanvas.value! as ICanvas
		render.checkPointInHitEvents = ['down', 'move', 'up', 'cancel']
		const boxWidth = render.boxWidth
		const boxHeight = render.boxHeight

		const strokeWidth = 30
		const radius = 110
		render.addShape(new IArc({
			startAngle:0,
			radius: radius - strokeWidth,
			endAngle: 360,
			x: boxWidth / 2,
			y: boxHeight / 2,
			stroke:"rgba(255,255,255,0.1)",
			strokeWidth: strokeWidth-10,
			lineCap: 'round',
			
		}, render
		))
		const iarc = new IArc({
			startAngle: 0,
			radius: radius - strokeWidth,
			endAngle: 0,
			x: boxWidth / 2,
			y: boxHeight / 2,
			strokeGradient:['45deg','#6d00c6 0%','#c33181 100%'],
			strokeWidth: strokeWidth-10,
			lineCap: 'round',
			
		}, render
		)
		render.addShape(iarc)
		render.addShape(new IArc({
			startAngle: 0,
			radius: radius,
			endAngle: 360,
			x: boxWidth / 2,
			y: boxHeight / 2,
			stroke:"rgba(255,255,255,0.1)",
			strokeWidth: strokeWidth,
			lineCap: 'round',
			
		}, render
		))
		const greearc = new IArc({
			startAngle: 0,
			radius: radius,
			endAngle: 275,
			x: boxWidth / 2,
			y: boxHeight / 2,
			strokeGradient:['45deg','#13794e 0%','#c33181 100%'],
			strokeWidth: strokeWidth,
			lineCap: 'round',
			
		}, render
		)
		render.addShape(greearc)
		
		render.addShape( new IArc({
			radius: radius+strokeWidth+5,
			endAngle: 360,
			x: boxWidth / 2,
			y: boxHeight / 2,
		
			strokeWidth: strokeWidth,
			stroke:"rgba(255,255,255,0.1)",
			lineCap: 'round',
			rotateCenter:'center'
		}, render
		))
		const shap1 = new IArc({
			startAngle: -45,
			radius: radius+strokeWidth+5,
			endAngle: 235,
			x: boxWidth / 2,
			y: boxHeight / 2,
		
			strokeWidth: strokeWidth,
			strokeGradient:['45deg','#abab00 0%','#c33181 100%'],
			lineCap: 'round',
			rotateCenter:'center'
		}, render
		)
		render.addShape(shap1)
		
		const shap2 = new IArc({
			startAngle: -45,
			radius: radius+strokeWidth+5,
			endAngle: -45,
			x: boxWidth / 2,
			y: boxHeight / 2,
			stroke: 'rgba(255, 239, 53, 1.0)',
			strokeWidth: strokeWidth-10,
			lineCap: 'round',
			rotateCenter:'center'
		}, render
		)
		render.addShape(shap2)
		const text= new IText({
			text:'0',
			fontSize:70,
			textAlign:'center',
			x: 0,
			y: boxHeight / 2 - 35,
			fill:'rgba(255, 239, 53, 1.0)',
		},render)
		render.addShape(text)
		const text2= new IText({
			text:'跑步圈数',
			fontSize:15,
			textAlign:'center',
			x: 0,
			y: boxHeight / 2 + 40,
			fill:"#c33181",
		},render)
		render.addShape(text2)
		drawerRule()
		render.render()
		
		tw1 = new Tween(shap2,render)
		.addTo({rotation:360},10*1000)
		.setLoop(-1)
		.onUpdate((progress:number)=>{
			text.setText((progress*100).toFixed(0))
		})
		.start()
		
		tw2 = new Tween(shap1,render)
		.addTo({rotation:360},10*1000)
		.setLoop(-1)
		.start()
		tw3 = new Tween(greearc,render)
		.addTo({rotation:-360},10*1000)
		.setLoop(-1)
		.start()
		tw4 = new Tween(iarc,render)
		.addTo({endAngle:360},10*1000)
		.setLoop(-1)
		.start()

	}

	const oninit = () => {
		xcanvas.value.init()
			.then(() => {
				drawer()
			})
	}

	onReady(() => {
		oninit()
	})
	
	onBeforeUnmount(() => {
		tw1?.destroy()
		tw2?.destroy()
		tw3?.destroy()
		tw4?.destroy()
		xcanvas.value?.destroy()
	})
</script>

<style>

</style>
最近更新