ENGLISH
CRender
CRender是干什么的?
- 它是一个基于canvas的矢量图形渲染插件。
- 它对图形提供动画和鼠标事件支持。
npm安装
$ npm install @jiaminghi/c-render
快速体验
<script src="http://lib.jiaminghi.com/crender/crender.map.js"></script>
<script src="http://lib.jiaminghi.com/crender/crender.min.js"></script>
<script>
const { CRender, extendNewGraph } = window.CRender
</script>
详细文档及示例请移步HomePage.
使用
import CRender from '@jiaminghi/c-redner'
const canvas = document.getElementById('canvas')
const render = new CRender(canvas)
const circle = render.add({ name: 'circle', ... })
Class CRender
类
class CRender {
}
实例属性
ctx
area
animationStatus
graphs
原型方法
add
CRender.prototype.add = function (config = {}) {
}
Clone
CRender.prototype.clone = function (graph) {
}
delGraph
CRender.prototype.delGraph = function (graph) {
}
delAllGraph
CRender.prototype.delAllGraph = function () {
}
drawAllGraph
CRender.prototype.drawAllGraph = function () {
}
clearArea
CRender.prototype.clearArea = function () {
}
launchAnimation
CRender.prototype.launchAnimation = function () {
}
Class Graph
实例属性
当添加一个图形时,你可以配置这些属性。
visible
shape
drag
hover
index
animationDelay
animationFrame
animationPause
hoverRect
mouseEnter
mouseOuter
click
Tip
启用图形的mouseEnter,mouseOuter,click等事件支持需要将hover
属性配置为true
。扩展的新图形需要配置hoverCheck方法以提供事件支持。
原型方法
attr
Graph.prototype.attr = function (attrName, change = undefined) {
}
animation
Graph.prototype.animation = async function (attrName, change, wait = false) {
}
animationEnd
Graph.prototype.animationEnd = function () {
}
pauseAnimation
Graph.prototype.pauseAnimation = function () {
}
playAnimation
Graph.prototype.playAnimation = function () {
}
生命周期
当向render中添加图形时,你可以配置如下几个方法,它们将在特定时刻被调用。
added
config = {
added ({ shape, style }) {
}
}
beforeDraw
config = {
beforeDraw ({ shape, style }, { ctx }) {
ctx.stroke = 'transparent'
}
}
drawed
config = {
drawed ({ shape, style }, { ctx }) {
}
}
beforeMove
config = {
beforeMove ({ offsetX, offsetY }, { shape, style }) {
}
}
moved
config = {
moved ({ offsetX, offsetY }, { shape, style }) {
}
}
beforeDelete
config = {
beforeDelete ({ shape, style }) {
}
}
deleted
config = {
deleted ({ shape, style }) {
}
}
Class Style
实例属性
fill
stroke
opacity
lineCap
lineJoin
lineDash
lineDashOffset
shadowBlur
shadowColor
shadowOffsetX
shadowOffsetY
lineWidth
graphCenter
scale
rotate
translate
hoverCursor
fontStyle
fontVarient
fontWeight
fontSize
fontFamily
textAlign
textBaseline
gradientColor
gradientType
gradientParams
gradientWith
gradientStops
colors
Tip
gradientColor
和gradientParams
被配置后将自动启用渐变。
原型方法
getStyle
Style.prototype.getStyle = function () {
}
示例
CRender提供如下基础矢量图形。
圆形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 圆心x轴坐标 |
ry | Number | 0 | 圆心y轴坐标 |
r | Number | 0 | 圆半径 |
const { area: [w, h] } = render
const circleConfig = {
name: 'circle',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
r: 50
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('shape', { r: 70 }, true)
this.animation('style', { shadowBlur: 20 })
},
mouseOuter (e) {
this.animation('shape', { r: 50 }, true)
this.animation('style', { shadowBlur: 0 })
}
}
const circle = render.add(circleConfig)
椭圆形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 圆心x轴坐标 |
ry | Number | 0 | 圆心y轴坐标 |
hr | Number | 0 | 横轴半径 |
vr | Number | 0 | 竖轴半径 |
const { area: [w, h] } = render
const ellipseConfig = {
name: 'ellipse',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
hr: 80,
vr: 30
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
shadowColor: '#66eece',
scale: [1, 1],
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { scale: [1.5, 1.5], shadowBlur: 20 })
},
mouseOuter (e) {
this.animation('style', { scale: [1, 1], shadowBlur: 0 })
}
}
const ellipse = render.add(ellipseConfig)
矩形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
x | Number | 0 | 矩形左上角x轴坐标 |
y | Number | 0 | 矩形左上角y轴坐标 |
w | Number | 0 | 矩形宽度 |
h | Number | 0 | 矩形高度 |
const { area: [w, h] } = render
const rectConfig = {
name: 'rect',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
x: w / 2 - rectWidth / 2,
y: h / 2 - rectHeight / 2,
w: rectWidth,
h: rectHeight
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer',
translate: [0, 0]
},
mouseEnter (e) {
this.animation('shape', { w: 400 }, true)
this.animation('style', { shadowBlur: 20, translate: [-100, 0] })
},
mouseOuter (e) {
this.animation('shape', { w: 200 }, true)
this.animation('style', { shadowBlur: 0, translate: [0, 0] })
}
}
const rect = render.add(rectConfig)
环形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 中心点x轴坐标 |
ry | Number | 0 | 中心点y轴坐标 |
r | Number | 0 | 环半径 |
const { area: [w, h] } = render
const ringConfig = {
name: 'ring',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
r: 50
},
style: {
stroke: '#9ce5f4',
lineWidth: 20,
hoverCursor: 'pointer',
shadowBlur: 0,
shadowColor: '#66eece'
},
mouseEnter (e) {
this.animation('style', { shadowBlur: 20, lineWidth: 30 })
},
mouseOuter (e) {
this.animation('style', { shadowBlur: 0, lineWidth: 20 })
}
}
const ring = render.add(ringConfig)
弧形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 中心点x轴坐标 |
ry | Number | 0 | 中心点y轴坐标 |
r | Number | 0 | 弧半径 |
startAngle | Number | 0 | 弧起始弧度值 |
endAngle | Number | 0 | 弧结束弧度值 |
clockWise | Boolean | true | 是否顺时针 |
const { area: [w, h] } = render
const arcConfig = {
name: 'arc',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
r: 60,
startAngle: 0,
endAngle: Math.PI / 3
},
style: {
stroke: '#9ce5f4',
lineWidth: 20,
shadowBlur: 0,
rotate: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('shape', { endAngle: Math.PI }, true)
this.animation('style', { shadowBlur: 20, rotate: -30, lineWidth: 30 })
},
mouseOuter (e) {
this.animation('shape', { endAngle: Math.PI / 3 }, true)
this.animation('style', { shadowBlur: 0, rotate: 0, lineWidth: 20 })
}
}
const arc = render.add(arcConfig)
扇形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 中心点x轴坐标 |
ry | Number | 0 | 中心点y轴坐标 |
r | Number | 0 | 扇形半径 |
startAngle | Number | 0 | 扇形起始弧度值 |
endAngle | Number | 0 | 扇形结束弧度值 |
clockWise | Boolean | true | 是否顺时针 |
const { area: [w, h] } = render
const sectorConfig = {
name: 'sector',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
r: 60,
startAngle: 0,
endAngle: Math.PI / 3
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
rotate: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('shape', { endAngle: Math.PI, r: 70 }, true)
this.animation('style', { shadowBlur: 20, rotate: -30, lineWidth: 30 })
},
mouseOuter (e) {
this.animation('shape', { endAngle: Math.PI / 3, r: 60 }, true)
this.animation('style', { shadowBlur: 0, rotate: 0, lineWidth: 20 })
}
}
const sector = render.add(sectorConfig)
正多边形
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
rx | Number | 0 | 中心点x轴坐标 |
ry | Number | 0 | 中心点y轴坐标 |
r | Number | 0 | 外接圆半径 |
side | Number | 0 | 边数 |
const { area: [w, h] } = render
const regPolygonConfig = {
name: 'regPolygon',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
rx: w / 2,
ry: h / 2,
r: 60,
side: 6
},
style: {
fill: '#9ce5f4',
hoverCursor: 'pointer',
shadowBlur: 0,
rotate: 0,
shadowColor: '#66eece'
},
mouseEnter (e) {
this.animation('shape', { endAngle: Math.PI, r: 100 }, true)
this.animation('style', { shadowBlur: 20, rotate: 180 })
},
mouseOuter (e) {
this.animation('shape', { endAngle: Math.PI / 3, r: 60 }, true)
this.animation('style', { shadowBlur: 0, rotate: 0 })
}
}
const regPolygon = render.add(regPolygonConfig)
折线
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
points | Array | [] | 构成折线的点 |
close | Boolean | false | 是否闭合折线 |
const { area: [w, h] } = render
const top = h / 3
const bottom = h / 3 * 2
const gap = w / 10
const beginX = w / 2 - gap * 2
const points = new Array(5).fill('').map((t, i) =>
[beginX + gap * i, i % 2 === 0 ? top : bottom])
const polylineConfig = {
name: 'polyline',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points
},
style: {
stroke: '#9ce5f4',
shadowBlur: 0,
lineWidth: 10,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { lineWidth: 20, shadowBlur: 20 })
},
mouseOuter (e) {
this.animation('style', { lineWidth: 10, shadowBlur: 0 })
}
}
const polyline = render.add(polylineConfig)
折线(闭合)
const { area: [w, h] } = render
const top = h / 3
const bottom = h / 3 * 2
const gap = w / 10
const beginX = w / 2 - gap * 2
const points = new Array(5).fill('').map((t, i) =>
[beginX + gap * i, i % 2 === 0 ? top : bottom])
points[2][1] += top * 1.3
const polylineClosedConfig = {
name: 'polyline',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points,
close: true
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
lineWidth: 10,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { shadowBlur: 20 }, true)
const pointsCloned = deepClone(this.shape.points)
pointsCloned[2][1] += top * 0.3
this.animation('shape', { points: pointsCloned })
},
mouseOuter (e) {
this.animation('style', { shadowBlur: 0 }, true)
const pointsCloned = deepClone(this.shape.points)
pointsCloned[2][1] -= top * 0.3
this.animation('shape', { points: pointsCloned })
}
}
const polylineClosed = render.add(polylineClosedConfig)
光滑曲线
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
points | Array | [] | 构成光滑曲线的点 |
close | Boolean | false | 是否闭合光滑曲线 |
const { area: [w, h] } = render
const top = h / 3
const bottom = h / 3 * 2
const gap = w / 10
const beginX = w / 2 - gap * 2
const points = new Array(5).fill('').map((t, i) =>
[beginX + gap * i, i % 2 === 0 ? top : bottom])
const smoothlineConfig = {
name: 'smoothline',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points
},
style: {
stroke: '#9ce5f4',
shadowBlur: 0,
lineWidth: 10,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { lineWidth: 20, shadowBlur: 20 })
},
mouseOuter (e) {
this.animation('style', { lineWidth: 10, shadowBlur: 0 })
}
}
const smoothline = render.add(smoothlineConfig)
光滑曲线(闭合)
import { getCircleRadianPoint } from '../../CRender/lib/util'
function getPoints (radius, centerPoint, pointNum) {
const PIDived = Math.PI * 2 / pointNum
const points = new Array(pointNum).fill('')
.map((foo, i) =>
getCircleRadianPoint(...centerPoint, radius, PIDived * i)
)
return points
}
const { area: [w, h] } = render
const radius = h / 3
const centerPoint = [w / 2, h / 2]
const smoothlineClosedConfig = {
name: 'smoothline',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points: getPoints(radius, centerPoint, 3),
close: true
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
lineWidth: 10,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { lineWidth: 20, shadowBlur: 20, rotate: 120 })
},
mouseOuter (e) {
this.animation('style', { lineWidth: 10, shadowBlur: 0, rotate: 0 })
},
setGraphCenter (e, { style }) {
if (e) {
const { movementX, movementY } = e
const [cx, cy] = style.graphCenter
style.graphCenter = [cx + movementX, cy + movementY]
} else {
style.graphCenter = [...centerPoint]
}
}
}
const smoothlineClosed = render.add(smoothlineClosedConfig)
贝塞尔曲线
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
points | Array | [] | 构成贝塞尔曲线的点 |
close | Boolean | false | 是否闭合贝塞尔曲线 |
const { area: [w, h] } = render
const offsetX = w / 2
const offsetY = h / 2
const points = [
[-100 + offsetX, -50 + offsetY],
[
[0 + offsetX, -50 + offsetY],
[0 + offsetX, 50 + offsetY],
[100 + offsetX, 50 + offsetY]
],
]
const bezierCurveConfig = {
name: 'bezierCurve',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points
},
style: {
lineWidth: 10,
stroke: '#9ce5f4',
shadowBlur: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e) {
this.animation('style', { lineWidth: 20, shadowBlur: 20 })
},
mouseOuter (e) {
this.animation('style', { lineWidth: 10, shadowBlur: 0 })
}
}
const bezierCurve = render.add(bezierCurveConfig)
贝塞尔曲线(闭合)
import { getCircleRadianPoint } from '../../CRender/lib/util'
function getPetalPoints (insideRadius, outsideRadius, petalNum, petalCenter) {
const PI2Dived = Math.PI * 2 / (petalNum * 3)
let points = new Array(petalNum * 3).fill('')
.map((foo, i) =>
getCircleRadianPoint(...petalCenter,
i % 3 === 0 ? insideRadius : outsideRadius,
PI2Dived * i)
)
const startPoint = points.shift()
points.push(startPoint)
points = new Array(petalNum).fill('')
.map(foo => points.splice(0, 3))
points.unshift(startPoint)
return points
}
const { area: [w, h] } = render
const petalCenter = [w / 2, h / 2]
const [raidus1, raidus2, raidus3, raidus4] = [h / 6, h / 2.5, h / 3, h / 2]
const bezierCurveClosedConfig = {
name: 'bezierCurve',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
shape: {
points: getPetalPoints(raidus1, raidus2, 6, petalCenter),
close: true
},
style: {
fill: '#9ce5f4',
shadowBlur: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer'
},
mouseEnter (e, { style: { graphCenter } }) {
this.animation('style', { lineWidth: 20, shadowBlur: 20 }, true)
this.animation('shape', { points: getPetalPoints(raidus3, raidus4, 6, graphCenter) })
},
mouseOuter (e, { style: { graphCenter } }) {
this.animation('style', { lineWidth: 10, shadowBlur: 0 }, true)
this.animation('shape', { points: getPetalPoints(raidus1, raidus2, 6, graphCenter) })
},
setGraphCenter (e, { style }) {
if (e) {
const { movementX, movementY } = e
const [cx, cy] = style.graphCenter
style.graphCenter = [cx + movementX, cy + movementY]
} else {
style.graphCenter = [...petalCenter]
}
}
}
const bezierCurveClosed = render.add(bezierCurveClosedConfig)
文本
shape属性
属性名 | 类型 | 默认值 | 注解 |
---|
content | String | '' | 文本内容 |
position | Array | [0, 0] | 文本起始位置 |
maxWidth | Number | Undefined | 文本最大宽度 |
rowGap | Number | 0 | 行间距 |
const { area: [w, h] } = render
const centerPoint = [w / 2, h / 2]
const hoverRect = [w / 2 - 100, h / 2 - 30 ,200, 60]
const textConfig = {
name: 'text',
animationCurve: 'easeOutBack',
hover: true,
drag: true,
hoverRect,
shape: {
content: 'CRender',
position: centerPoint,
maxWidth: 200
},
style: {
fill: '#9ce5f4',
fontSize: 50,
shadowBlur: 0,
rotate: 0,
shadowColor: '#66eece',
hoverCursor: 'pointer',
scale: [1, 1],
rotate: 0
},
mouseEnter (e) {
this.animation('style', { shadowBlur: 20, scale: [1.5, 1.5], rotate: 30 })
},
mouseOuter (e) {
this.animation('style', { shadowBlur: 0, scale: [1, 1], rotate: 0 })
},
moved (e, { hoverRect }) {
const { movementX, movementY } = e
hoverRect[0] += movementX
hoverRect[1] += movementY
}
}
const text = render.add(textConfig)
Tip
扩展新图形
CRender提供了一个方法去扩展新的图形,你可以自定义想要的图形。
import { extendNewGraph } from '@jiaminghi/c-render'
const graphName = 'newGraph'
const graphConfig = {
shape: { ... },
}
extendNewGraph(graphName, graphConfig)
extendNewGraph
function extendNewGraph (name, config) {
}
图形配置属性
shape (必须)
config = {
shape: {
}
}
validator (必须)
config = {
validator ({ shape }) {
}
}
draw (必须)
config = {
draw ({ ctx }, { shape }) {
}
}
hoverCheck (可选)
config = {
validator ([offsetX, offsetY], { shape }) {
}
}
setGraphCenter (可选)
config = {
setGraphCenter ([offsetX, offsetY], { style }) {
}
}
move (Optional)
config = {
move ([offsetX, offsetY], { shape }) {
}
}
扩展示例
import { extendNewGraph } from '@jiaminghi/c-render'
const circle = {
shape: {
rx: 0,
ry: 0,
r: 0
},
validator ({ shape }) {
const { rx, ry, r } = shape
if (typeof rx !== 'number' || typeof ry !== 'number' || typeof r !== 'number') {
console.error('Shape configuration is abnormal!')
return false
}
return true
},
draw ({ ctx }, { shape }) {
ctx.beginPath()
const { rx, ry, r } = shape
ctx.arc(rx, ry, r, 0, Math.PI * 2)
ctx.fill()
ctx.stroke()
ctx.closePath()
},
hoverCheck (position, { shape }) {
const { rx, ry, r } = shape
return checkPointIsInCircle(rx, ry, r, position)
},
setGraphCenter (e, { shape, style }) {
const { rx, ry } = shape
style.graphCenter = [rx, ry]
},
move ({ movementX, movementY }, { shape }) {
this.attr('shape', {
rx: shape.rx + movementX,
ry: shape.ry + movementY
})
}
}
extendNewGraph('circle', circle)
相关支持