123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <template>
- <view class="page" id="page-canvas">
- <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: {{testToBlobResult}}</text>
- </view>
- <!-- #endif -->
- <button class="canvas-drawing-button" id="toDataURL" @click="canvasToDataURL">canvasToDataURL</button>
- <view class="text-group" v-if="dataBase64.length>0">
- <text>canvasToDataURL:</text>
- <text>{{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">{{testCanvasContext}}</text>
- </view>
- <view class="text-group">
- <text>测试 ToDataURL 结果:</text>
- <text id="testToDataURLResult">{{testToDataURLResult}}</text>
- </view>
- <view class="text-group">
- <text>测试 createImage 结果:</text>
- <text id="testCreateImage">{{testCreateImage}}</text>
- </view>
- <view class="text-group">
- <text>测试 createPath2D 结果:</text>
- <text id="testCreatePath2D">{{testCreatePath2D}}</text>
- </view>
- <view class="text-group">
- <text>测试 createCanvasContextAsync 结果:</text>
- <view @click="testCreateContextAsync" id="createCanvasContextAsync">{{testCanvasCtx}}</view>
- </view>
- <canvas-child ref="canvas-child"></canvas-child>
- </scroll-view>
- </view>
- </template>
- <script>
- import CanvasChild from './canvas-child.uvue'
- 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);
- }
- export default {
- components: {
- CanvasChild
- },
- data() {
- return {
- title: 'Context2D',
- canvas: null as UniCanvasElement | null,
- canvasContext: null as CanvasContext | null,
- renderingContext: null as CanvasRenderingContext2D | 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
- }
- },
- computed: {
- testCanvasCtx() {
- return this.testCanvasCtx1 && this.testCanvasCtx2
- }
- },
- onLoad() {
- // HBuilderX 4.25+
- // 异步调用方式, 跨平台写法
- uni.createCanvasContextAsync({
- id: 'canvas',
- component: this,
- success: (context : CanvasContext) => {
- this.canvasContext = context;
- this.renderingContext = context.getContext('2d')!;
- this.canvas = this.renderingContext!.canvas;
- hidpi(this.canvas!);
- this.canvasWidth = this.canvas!.width;
- this.canvasHeight = this.canvas!.height;
- // #ifdef WEB
- context.toBlob((blob : Blob) => {
- this.testToBlobResult = (blob.size > 0 && blob.type == 'image/jpeg')
- }, 'image/jpeg', 0.95);
- // #endif
- // #ifdef APP || WEB || MP
- setTimeout(() => {
- this.testToDataURLResult = this.canvasContext!.toDataURL().startsWith('data:image/png;base64')
- }, 50)
- // #endif
- this.testCanvasContext = true
- }
- })
- uni.$on('canvasChildReady', this.onChildReady)
- },
- onReady() {
- // 同步调用方式,仅支持 app/web
- // let canvas = uni.getElementById("canvas") as UniCanvasElement
- // this.renderingContext = canvas.getContext("2d")
- // hidpi(canvas);
- // this.canvas = canvas;
- // this.canvasWidth = canvas.width;
- // this.canvasHeight = canvas.height;
- },
- onUnload() {
- uni.$off('canvasChildReady', this.onChildReady)
- if (this.taskId > 0) {
- this.stopAnimationFrame()
- }
- },
- methods: {
- // #ifdef WEB
- canvasToBlob() {
- this.canvasContext!.toBlob((blob : Blob) => {
- this.testToBlobResult = (blob.size > 0 && blob.type == 'image/jpeg')
- }, 'image/jpeg', 0.95)
- },
- // #endif
- canvasToDataURL() {
- this.dataBase64 = this.canvasContext!.toDataURL()
- },
- onCreateImage() {
- this.renderingContext!.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
- let image = this.canvasContext!.createImage();
- image.src = "/static/logo.png"
- image.onload = () => {
- this.testCreateImage = true
- this.renderingContext?.drawImage(image, 0, 0, 100, 100);
- }
- },
- onCreatePath2D() {
- this.renderingContext!.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
- const context = this.renderingContext!
- let path2D = this.canvasContext!.createPath2D()
- this.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);
- },
- startAnimationFrame() {
- this.taskId = this.canvasContext!.requestAnimationFrame((timestamp : number) => {
- this.testFrameCount++
- this.updateFPS(timestamp)
- this.startAnimationFrame()
- })
- },
- stopAnimationFrame() {
- this.canvasContext!.cancelAnimationFrame(this.taskId)
- this.taskId = 0
- },
- updateFPS(timestamp : number) {
- this.frameCount++
- if (timestamp - this.lastTime >= 1000) {
- const timeOfFrame = (1000 / this.frameCount)
- this.renderingContext!.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
- this.renderingContext!.fillText(`${this.frameCount} / ${timeOfFrame.toFixed(3)}ms`, 10, 18)
- this.frameCount = 0
- this.lastTime = timestamp
- }
- },
- testCreateContextAsync() {
- uni.createCanvasContextAsync({
- id: 'canvas',
- component: this,
- success: () => {
- this.testCanvasCtx1 = true
- }
- })
- // no `component` param
- uni.createCanvasContextAsync({
- id: 'canvas',
- success: () => {
- this.testCanvasCtx2 = true
- }
- })
- },
- onChildReady() {
- const childInstance = (this.$refs['canvas-child'] as ComponentPublicInstance);
- this.testCounter = childInstance.$data['testCounter'] as number;
- }
- }
- }
- </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>
|