ICanvas - Library
警告
本画布文档由Cursor Ai根据我的uts文件自动编写的文档,如果有遇到描述错误的地方请通知我更新。
兼容
| Harmony | H5 | PC | android | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|---|---|---|---|---|---|---|---|---|
| ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | ☑️ | 4.75+ | 1.1.16+ |
演示
下面的演示中的元素可以拖动。
预览
介绍
可以用于各种复杂的排版,动画,一些Lot实时绘制的动画场景,海报绘制,二给码等元素。 这是一个非常强大的绘画引擎.主要包含以下几个部分:
- 一个图形绘制系统
- 一个事件控制系统
- 一个动画控制系统
示例源码
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">绘画库 ICanvas</x-text>
<x-text color="#999999" class="mb-8">有独立的事件及动画系统,下面绘制的元素都可点击、拖动。绘制走 x-skia-u,命中由 Skia Path2D 完成。</x-text>
</x-sheet>
<view class="xICanvasHost" :id="canvasId" ref="hostRef" :style="{width: canvasW + 'px', height: canvasH + 'px'}">
<x-skia-u ref="skiaRef" :width="canvasW" :height="canvasH" @ready="onSkiaReady"></x-skia-u>
<view class="xICanvasHit"
@click="bindEvents"
@touchstart="bindEvents"
@touchmove.stop="bindEvents"
@touchend="bindEvents"
@touchcancel="bindEvents"
@mousedown="bindEvents"
@mousemove="bindEvents"
@mouseup="bindEvents"
<!-- #ifdef WEB -->
@mouseleave="bindEvents"
<!-- #endif -->
></view>
</view>
<x-cell url="/pages/libs/canvasFlip" title="翻页效果"></x-cell>
<x-cell url="/pages/libs/canvasRotarySwitch" title="旋转开关示例"></x-cell>
<x-cell url="/pages/libs/canvasWatchSportOne" title="运动环示例"></x-cell>
<x-cell url="/pages/libs/canvasVoiceLine" title="语音录制波"></x-cell>
<x-cell url="/pages/libs/canvasPic" title="海报绘制演示"></x-cell>
<x-cell url="/pages/libs/canvasLayout" title="自动排版"></x-cell>
<x-cell url="/pages/libs/canvasGroup" title="组Group"></x-cell>
<x-cell url="/pages/libs/canvasGravity" title="重力插件"></x-cell>
<view style="height:150px"></view>
</template>
<script setup>
import { ICanvas,CanvasEventType, ICanvasEvent ,ICanvasOptional ,
IRect,IText,Tween,ImageShape,Path2DShape,IRing,IArc,ISector,IRegularPolygon,
ILinePolygon,ICircle,IEllipse,IStar
} from '@/uni_modules/tmx-ui';
const canvasId = "xCanvas-" + Math.random().toString(16).substring(4)
const canvasW = Math.max(1, Math.floor(uni.getWindowInfo().windowWidth))
const canvasH = 350
const skiaRef = ref(null)
const hostRef = ref(null)
const proxy = getCurrentInstance()?.proxy ?? null;
const xcanvas = shallowRef<ICanvas>(new ICanvas({ canvasId: canvasId,component: proxy } as ICanvasOptional));
// 添加受支持的事件。
xcanvas.value.checkPointInHitEvents = ['down','move','up','click']
let tw1 = null as Tween | null
let tw2 = null as Tween | null
let tw3 = null as Tween | null
const initdrawer = () => {
if (xcanvas.value == null) return;
const render = xcanvas.value! as ICanvas
const text = new IText({
draggable: true,
text:
`这是一个非常强劲的图形渲染库\n有独立的事件及动画系统\n主要是用来制作营销动画交互及海报等场景\n有了它之后编排海报或者营销动画非常简单.`,
fill: "#587cff",
textAlign: 'right'
}, render)
const textBounds = text.getBoundRect();
text.setY(render.boxHeight - textBounds.height - 44)
text.setX(render.boxWidth - textBounds.width)
text.addEventListener('click', (evt) => {
text.setFill(text.toggleStatus ? '#f93e41' : '#587cff')
render.update()
})
render.addShape(text)
let sp = new ImageShape({
draggable: true,
src:'https://cdn.tmui.design/xui/tmui4.0banner1.jpg',
width: 100,
height: 56,
x: render.boxWidth - 100,
rotateCenter: "center",
y: 20
}, render)
sp.addEventListener('click', (evt) => {
sp.setScaleX(sp.toggleStatus ? 1.2 : 1)
sp.setScaleY(sp.toggleStatus ? 1.2 : 1)
render.update()
})
render.addShape(sp)
let pathsape = new Path2DShape({
draggable: true,
fill: "#587cff", offsetX: 50, width: 100
}, render)
pathsape.parsePathData('M50,0a50,50,0,1,0,50,50A50,50,0,0,0,50,0ZM66,21.25a8,8,0,1,1-8,8A8,8,0,0,1,66,21.25Zm-32,0a8,8,0,1,1-8,8A8,8,0,0,1,34,21.25Zm-14,38H80C75,85.25,25,85.25,20,59.25Z')
pathsape.addEventListener('click', (evt) => {
pathsape.setFill(pathsape.toggleStatus ? '#ff0000' : '#587cff')
render.update()
})
render.addShape(pathsape)
const rect = new IRect({
draggable: true,
x: 100, y: 100, width: 100, height: 50, fill: "#572cff", rotation: 45, opacity: 0.6,rotateCenter:'center'
}, render)
const rect2 = new IRect({
draggable: true,
x: 100, y: 100, width: 100, height: 50, fill: "#d348e5", radius: 8
}, render)
// rect2.drag = (event:CanvasEventType,parentEvent:ICanvasEvent)=>{
// // let x = rect2.x-parentEvent.detail[0].moveLenX
// // x = Math.max(0,Math.min(150,x))
// // rect2.x = x
// rect2.x-=parentEvent.detail[0].moveLenX
// rect2.y-=parentEvent.detail[0].moveLenY
// }
rect2.addEventListener('click', (evt) => {
rect2.setFill(rect2.toggleStatus ? '#ff6939' : '#81144f')
render.update()
})
rect.addEventListener('click', (evt) => {
rect.setFill(rect.toggleStatus ? '#ef3c9e' : '#ffac69')
render.update()
})
render.addShape(rect2)
render.addShape(rect)
const ring = new IRing({
draggable: true,
fill: "#ff0000",
x: 50,
y: 110,
endAngle: 90
}, render)
ring.addEventListener('click', (evt) => {
ring.setFill(ring.toggleStatus ? '#ffac69' : '#ff0000')
render.update()
})
render.addShape(ring)
const arc = new IArc({
draggable: true,
stroke: "#ff0000",
x: 40,
y: 160,
strokeWidth: 8,
lineJoin: 'round',
lineCap: "round",
lineDashOffset: 5,
endAngle: 135
}, render)
arc.addEventListener('click', (evt) => {
let target = evt.target as IArc
target.setStroke(target.stroke == '#ff0000' ? '#ffac69' : '#ff0000')
render.update()
})
render.addShape(arc)
for (let i = 0; i < 24; i++) {
const colortest = `rgb(255,${10 * (i + 1)},${10 * (i + 1)})`
const tarc = new ISector({
draggable: true,
fill: colortest,
x: 240,
y: 120,
radius: i * 2 + 14,
startAngle: 15 * i,
endAngle: 15 * (i + 1)
}, render)
tarc.addEventListener('click', (evt) => {
tarc.setFill(tarc.toggleStatus ? '#ffc61e' : colortest)
render.update()
})
render.addShape(tarc)
}
const text2 = new IText({
draggable: true,
text: "点我保存画布图片!",
fill: "#ffffff",
textAlign: 'center',
padding:16,
fontSize: 16,
lineHeight: 1,
bubbleEvent: true,
textBaseline: 'middle',
radius:12,
textBgColor:"rgb(5, 121, 255)"
}, render)
text2.toggle((status : boolean, target : any) => {
if (status) {
text2.setText("已导出预览图片")
text2.setTextBgColor('#ff0000')
render.getImage().then((imgpath:string)=>{
console.log(imgpath)
uni.previewImage({
current:imgpath,
urls:[imgpath]
})
})
} else {
text2.setText("点我保存画布图片")
text2.setTextBgColor('rgb(5, 121, 255)')
}
render.update()
})
const text2Bounds = text2.getBoundRect();
text2.setY(render.boxHeight - text2Bounds.height)
render.addShape(text2)
const polygon = new IRegularPolygon({
draggable: true,
sides: 5,
x: 50,
y: 250,
fill: "#ff0000",
}, render)
polygon.addEventListener('click', (evt) => {
polygon.setSides(polygon.toggleStatus ? 6 : 5)
render.update()
})
render.addShape(polygon)
const linepolygon = new ILinePolygon({
draggable: true,
points: [0, 0, 40, 60, 80, 0, 120, 60, 160, 0, 200, 60],
x: 90,
y: 220,
strokeWidth: 8,
stroke: "#ff0000",
lineCap: 'round',
opacity: 0.5,
tension: 0.5,
closed: false,
bezier: true
}, render)
linepolygon.addEventListener('click', (evt) => {
linepolygon.setStroke(linepolygon.toggleStatus ? "#ffff00" : "#ff0000")
render.update()
})
render.addShape(linepolygon)
const circle = new ICircle({
draggable: true,
x: 220,
y: 200,
strokeWidth: 8,
stroke: "#18e7dd",
lineCap: 'round',
fill: "#5f5cf0"
}, render)
circle.addEventListener('click', (evt) => {
circle.setStroke(circle.toggleStatus ? "#5f5cf0" : "#18e7dd")
render.update()
})
render.addShape(circle)
const ellipse = new IEllipse({
draggable: true,
x: 220,
y: 200,
strokeWidth: 6,
stroke: "#f08200",
lineCap: 'round',
// lineDash:[2,0,0,8]
}, render)
ellipse.addEventListener('click', (evt) => {
ellipse.setStroke(ellipse.toggleStatus ? "#f4483b" : "#f08200")
// ellipse.setLineDash(ellipse.toggleStatus ? [2,0,0,0] : [2,0,0,8])
render.update()
})
render.addShape(ellipse)
const star = new IStar({
draggable: true,
x: 280,
y: 240,
strokeWidth: 6,
numPoints: 6,
stroke: "rgba(255,0,0,1)",
fill: "rgba(255,0,0,0.5)"
}, render)
star.addEventListener('click', (evt) => {
star.setStroke(star.toggleStatus ? "#f4483b" : "rgba(255,0,0,1)")
star.setNumPoints(star.toggleStatus ? 5 : 6)
render.update()
})
render.addShape(star)
render.render()
// tw1 = new Tween(rect, render)
// .to({ radius: 24 })
// .setYoyo(true)
// .setLoop(-1)
// .start()
// tw2 = new Tween(polygon, render)
// .to({ scaleX: 1.3, scaleY: 1.3 })
// .setYoyo(true)
// .setLoop(-1)
// .start()
// tw3 = new Tween(ring, render)
// .addTo({ endAngle: 270 })
// // .addTo({ x: 100 })
// .setYoyo(true)
// .setLoop(-1)
// .onComplete(() => {
// console.log('ok')
// })
// .start()
}
const bindEvents = (evt : UniTouchEvent | UniPointerEvent | UniMouseEvent) => {
xcanvas.value.bindEvent(evt)
}
const onSkiaReady = () => {
const ctx = skiaRef.value?.getContext("2d")
if (ctx == null) return
xcanvas.value.setHitElement(hostRef.value)
xcanvas.value.onSurfaceReady(ctx, initdrawer)
}
onPageScroll(() => {
xcanvas.value.syncLayout()
})
onBeforeUnmount(() => {
tw1?.stop()
tw2?.stop()
tw3?.stop()
xcanvas.value?.destroy()
})
</script>
<style>
.xICanvasHost {
position: relative;
width: 100%;
overflow: hidden;
}
.xICanvasHit {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
</style>