文件
OmniCard/mpuniapp/pages/component/canvas/canvas.uvue

297 行
8.5 KiB
Plaintext

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="page" id="page-canvas">
<page-intro content="本页演示 canvas 画布组件:toDataURL、createImage、createPath2D、requestAnimationFrame 等;可跳转 CanvasContext API 子页,展示绘图与异步上下文。"></page-intro>
<canvas id="canvas" class="canvas-element"></canvas>
<scroll-view class="scroll-view">
<!-- #ifdef WEB -->
<button class="canvas-drawing-button" @click="canvasToBlob">canvasToBlob</button>
<view>
<text>testToBlobResult: {{data.testToBlobResult}}</text>
</view>
<!-- #endif -->
<button class="canvas-drawing-button" id="toDataURL" @click="canvasToDataURL">canvasToDataURL</button>
<view class="text-group" v-if="data.dataBase64.length>0">
<text>canvasToDataURL:</text>
<text>{{data.dataBase64.slice(0,22)}}...</text>
</view>
<button @click="onCreateImage">createImage</button>
<button @click="onCreatePath2D">createPath2D</button>
<button @click="startAnimationFrame">requestAnimationFrame</button>
<button @click="stopAnimationFrame">cancelAnimationFrame</button>
<view style="padding: 8px 10px;">CanvasContext API 演示</view>
<navigator url="./canvas-context">
<button>CanvasContext API</button>
</navigator>
<view class="text-group">
<text>获取 CanvasContext 结果:</text>
<text id="testCanvasContext">{{data.testCanvasContext}}</text>
</view>
<view class="text-group">
<text>测试 ToDataURL 结果:</text>
<text id="testToDataURLResult">{{data.testToDataURLResult}}</text>
</view>
<view class="text-group">
<text>测试 createImage 结果:</text>
<text id="testCreateImage">{{data.testCreateImage}}</text>
</view>
<view class="text-group">
<text>测试 createPath2D 结果:</text>
<text id="testCreatePath2D">{{data.testCreatePath2D}}</text>
</view>
<view class="text-group">
<text>测试 createCanvasContextAsync 结果:</text>
<text @click="testCreateContextAsync" id="createCanvasContextAsync">{{testCanvasCtx}}</text>
</view>
<canvas-child ref="canvasChildRef"></canvas-child>
</scroll-view>
</view>
</template>
<script setup lang="uts">
import CanvasChild from './canvas-child.uvue'
const instance = getCurrentInstance()!.proxy
type DataType = {
title: string;
canvas: UniCanvasElement | null;
canvasContext: CanvasContext | null;
renderingContext: CanvasRenderingContext2D | null;
canvasWidth: number;
canvasHeight: number;
dataBase64: string;
taskId: number;
lastTime: number;
frameCount: number;
testCanvasContext: boolean;
testToBlobResult: boolean;
testToDataURLResult: boolean;
testCreateImage: boolean;
testCreatePath2D: boolean;
testFrameCount: number;
testCanvasCtx1: boolean;
testCanvasCtx2: boolean;
testCounter: number;
}
const data = reactive({
title: 'Context2D',
canvas: null,
canvasContext: null,
renderingContext: null,
canvasWidth: 0,
canvasHeight: 0,
dataBase64: '',
taskId: 0,
lastTime: 0,
frameCount: 0,
testCanvasContext: false,
testToBlobResult: false,
testToDataURLResult: false,
testCreateImage: false,
testCreatePath2D: false,
testFrameCount: 0,
testCanvasCtx1: false,
testCanvasCtx2: false,
testCounter: 0
} as DataType)
const canvasChildRef = ref<ComponentPublicInstance | null>(null)
const testCanvasCtx = computed(() => {
return data.testCanvasCtx1 && data.testCanvasCtx2
})
function hidpi(canvas : UniCanvasElement) {
const context = canvas.getContext("2d")!;
const dpr = uni.getWindowInfo().pixelRatio;
canvas.width = canvas.offsetWidth * dpr;
canvas.height = canvas.offsetHeight * dpr;
context.scale(dpr, dpr);
}
// #ifdef WEB
const canvasToBlob = () => {
data.canvasContext!.toBlob((blob : Blob) => {
data.testToBlobResult = (blob.size > 0 && blob.type == 'image/jpeg')
}, 'image/jpeg', 0.95)
}
// #endif
const canvasToDataURL = () => {
data.dataBase64 = data.canvasContext!.toDataURL()
}
const onCreateImage = () => {
data.renderingContext!.clearRect(0, 0, data.canvasWidth, data.canvasHeight)
let image = data.canvasContext!.createImage();
image.src = "/static/test-image/logo.png"
image.onload = () => {
data.testCreateImage = true
data.renderingContext?.drawImage(image, 0, 0, 100, 100);
}
}
const onCreatePath2D = () => {
data.renderingContext!.clearRect(0, 0, data.canvasWidth, data.canvasHeight)
const context = data.renderingContext!
let path2D = data.canvasContext!.createPath2D()
data.testCreatePath2D = true
const amplitude = 64;
const wavelength = 64;
for (let i = 0; i < 5; i++) {
const x1 = 0 + (i * wavelength);
const y1 = 128;
const x2 = x1 + wavelength / 4;
const y2 = y1 - amplitude;
const x3 = x1 + 3 * wavelength / 4;
const y3 = y1 + amplitude;
const x4 = x1 + wavelength;
const y4 = y1;
context.moveTo(x1, y1);
path2D.bezierCurveTo(x2, y2, x3, y3, x4, y4);
}
context.stroke(path2D);
}
const updateFPS = (timestamp : number) => {
data.frameCount++
if (timestamp - data.lastTime >= 1000) {
const timeOfFrame = (1000 / data.frameCount)
data.renderingContext!.clearRect(0, 0, data.canvasWidth, data.canvasHeight)
data.renderingContext!.fillText(`${data.frameCount} / ${timeOfFrame.toFixed(3)}ms`, 10, 18)
data.frameCount = 0
data.lastTime = timestamp
}
}
type StartAnimationFrameType = () => void
let startAnimationFrame: StartAnimationFrameType = () => {}
startAnimationFrame = () => {
data.taskId = data.canvasContext!.requestAnimationFrame((timestamp : number) => {
data.testFrameCount++
updateFPS(timestamp)
startAnimationFrame()
})
}
const stopAnimationFrame = () => {
data.canvasContext!.cancelAnimationFrame(data.taskId)
data.taskId = 0
}
const testCreateContextAsync = () => {
uni.createCanvasContextAsync({
id: 'canvas',
component: instance!,
success: () => {
data.testCanvasCtx1 = true
}
})
uni.createCanvasContextAsync({
id: 'canvas',
success: () => {
data.testCanvasCtx2 = true
}
})
}
const onChildReady = (count: number) => {
// 通过事件传递数据
data.testCounter = count
}
// TODO 暂时使用 onReady NativeView生命周期存在问题
onReady(() => {
uni.createCanvasContextAsync({
id: 'canvas',
component: instance!,
success: (context : CanvasContext) => {
data.canvasContext = context;
data.renderingContext = context.getContext('2d')!;
data.canvas = data.renderingContext!.canvas;
hidpi(data.canvas!);
data.canvasWidth = data.canvas!.width;
data.canvasHeight = data.canvas!.height;
// #ifdef WEB
context.toBlob((blob : Blob) => {
data.testToBlobResult = (blob.size > 0 && blob.type == 'image/jpeg')
}, 'image/jpeg', 0.95);
// #endif
// #ifdef APP || WEB || MP
setTimeout(() => {
data.testToDataURLResult = data.canvasContext!.toDataURL().startsWith('data:image/png;base64')
}, 50)
// #endif
data.testCanvasContext = true
}
})
})
onReady(() => {
// 同步调用方式,仅支持 app/web
// let canvas = uni.getElementById("canvas") as UniCanvasElement
// data.renderingContext = canvas.getContext("2d")
// hidpi(canvas);
// data.canvas = canvas;
// data.canvasWidth = canvas.width;
// data.canvasHeight = canvas.height;
})
onLoad(() => {
//监听canvasChildReady从onReady调整到onLoad,避免监听时机过晚导致无法收到此事件
uni.$on('canvasChildReady', onChildReady)
})
onUnload(() => {
uni.$off('canvasChildReady', onChildReady)
if (data.taskId > 0) {
stopAnimationFrame()
}
})
defineExpose({
data,
canvasToDataURL,
onCreateImage,
onCreatePath2D
})
</script>
<style>
.page {
flex: 1;
height: 100%;
overflow: hidden;
}
.scroll-view {
flex: 1;
}
.canvas-element {
width: 100%;
height: 250px;
background-color: #ffffff;
}
.btn-to-image {
margin: 10px;
}
.text-group {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
}
</style>