You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2045 lines
29 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import beziercurve from '../bezier-curve'
import {
calcLength,
getPointOnQuadraticBezier,
getTensionPointsClosed,
expandPoints
} from '../bezier-curve/core/path2d'
import {
deepClone,
eliminateBlur,
checkPointIsInCircle,
getTwoPointDistance,
checkPointIsInSector,
getRegularPolygonPoints,
checkPointIsInPolygon,
checkPointIsNearPolyline,
checkPointIsInRect
} from '../plugin/util'
import {
drawPolylinePath,
drawBezierCurvePath
} from '../plugin/canvas'
const {
polylineToBezierCurve,
bezierCurveToPolyline
} = beziercurve
export 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('Circle shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
const {
rx,
ry,
r
} = shape
ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2)
ctx.fill()
ctx.stroke()
ctx.closePath()
// ctx.draw()
},
hoverCheck(position, {
shape
}) {
const {
rx,
ry,
r
} = shape
return checkPointIsInCircle(position, rx, ry, r)
},
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
})
}
}
export const ellipse = {
shape: {
rx: 0,
ry: 0,
hr: 0,
vr: 0
},
validator({
shape
}) {
const {
rx,
ry,
hr,
vr
} = shape
if (typeof rx !== 'number' || typeof ry !== 'number' || typeof hr !== 'number' || typeof vr !== 'number') {
console.error('Ellipse shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
let {
rx,
ry,
hr,
vr
} = shape
ctx.ellipse(rx, ry, hr > 0 ? hr : 0.01, vr > 0 ? vr : 0.01, 0, 0, Math.PI * 2)
ctx.fill()
ctx.stroke()
ctx.closePath()
// ctx.draw()
},
hoverCheck(position, {
shape
}) {
const {
rx,
ry,
hr,
vr
} = shape
const a = Math.max(hr, vr)
const b = Math.min(hr, vr)
const c = Math.sqrt(a * a - b * b)
const leftFocusPoint = [rx - c, ry]
const rightFocusPoint = [rx + c, ry]
const distance = getTwoPointDistance(position, leftFocusPoint) + getTwoPointDistance(position,
rightFocusPoint)
return distance <= 2 * a
},
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
})
}
}
export const rect = {
shape: {
x: 0,
y: 0,
w: 0,
h: 0
},
validator({
shape
}) {
const {
x,
y,
w,
h
} = shape
if (typeof x !== 'number' || typeof y !== 'number' || typeof w !== 'number' || typeof h !== 'number') {
console.error('Rect shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
let {
x,
y,
w,
h
} = shape
ctx.rect(x, y, w, h)
ctx.fill()
ctx.stroke()
ctx.closePath()
// ctx.draw()
},
hoverCheck(position, {
shape
}) {
let {
x,
y,
w,
h
} = shape
return checkPointIsInRect(position, x, y, w, h)
},
setGraphCenter(e, {
shape,
style
}) {
const {
x,
y,
w,
h
} = shape
style.graphCenter = [x + w / 2, y + h / 2]
},
move({
movementX,
movementY
}, {
shape
}) {
this.attr('shape', {
x: shape.x + movementX,
y: shape.y + movementY
})
}
}
export const rectRound = {
shape: {
x: 0,
y: 0,
w: 0,
h: 0,
radius:[0,0,0,0],
close:false,//true时为填充否则描边。
},
validator({
shape
}) {
const {
x,
y,
w,
h
} = shape
if (typeof x !== 'number' || typeof y !== 'number' || typeof w !== 'number' || typeof h !== 'number') {
console.error('Rect shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
let {
x,
y,
w,
h,
radius,
close
} = shape
if(typeof radius ==='number'){
radius = [radius,radius,radius,radius]
}
const cxt = ctx;
let width = w,height = h;
var r0 = radius[0],r1 = radius[1],r2 = radius[2],r3 = radius[3];
cxt.beginPath();
//从右下角顺时针绘制弧度从0到1/2PI
cxt.arc(width - r0+x, height - r0+y, r0, 0, Math.PI / 2);
//矩形下边线
cxt.lineTo(r1+x, height+y);
//左下角圆弧弧度从1/2PI到PI
cxt.arc(r1+x, height - r1+y, r1, Math.PI / 2, Math.PI);
//矩形左边线
cxt.lineTo(x, r2+y);
//左上角圆弧弧度从PI到3/2PI
cxt.arc(r2+x, r2+y, r2, Math.PI, Math.PI * 3 / 2);
//上边线
cxt.lineTo(width - r3+x, y);
//右上角圆弧
cxt.arc(width - r3+x, r3+y, r3, Math.PI * 3 / 2, Math.PI * 2);
//右边线
cxt.lineTo(width+x, height+y-r0);
ctx.stroke()
if(close){
ctx.fill()
}
cxt.closePath();
},
hoverCheck(position, {
shape,style,
}) {
let {
x,
y,
w,
h
} = shape
let {lineWidth} = style;
return checkPointIsInRect(position, x-lineWidth, y-lineWidth, w+lineWidth, h+lineWidth)
},
setGraphCenter(e, {
shape,
style
}) {
const {
x,
y,
w,
h
} = shape
style.graphCenter = [x + w / 2, y + h / 2]
},
move({
movementX,
movementY
}, {
shape
}) {
this.attr('shape', {
x: shape.x + movementX,
y: shape.y + movementY
})
}
}
export const ring = {
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('Ring shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
const {
rx,
ry,
r
} = shape
ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2)
ctx.stroke()
ctx.closePath()
// ctx.draw()
},
hoverCheck(position, {
shape,
style
}) {
const {
rx,
ry,
r
} = shape
const {
lineWidth
} = style
const halfLineWidth = lineWidth / 2
const minDistance = r - halfLineWidth
const maxDistance = r + halfLineWidth
const distance = getTwoPointDistance(position, [rx, ry])
return (distance >= minDistance && distance <= maxDistance)
},
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
})
}
}
export const arc = {
shape: {
rx: 0,
ry: 0,
r: 0,
startAngle: 0,
endAngle: 0,
clockWise: true
},
validator({
shape
}) {
const keys = ['rx', 'ry', 'r', 'startAngle', 'endAngle']
if (keys.find(key => typeof shape[key] !== 'number')) {
console.error('Arc shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
const {
rx,
ry,
r,
startAngle,
endAngle,
clockWise
} = shape
ctx.arc(rx, ry, r > 0 ? r : 0.001, startAngle, endAngle, !clockWise)
ctx.stroke()
ctx.closePath()
// ctx.draw(true)
},
hoverCheck(position, {
shape,
style
}) {
const {
rx,
ry,
r,
startAngle,
endAngle,
clockWise
} = shape
const {
lineWidth
} = style
const halfLineWidth = lineWidth / 2
const insideRadius = r - halfLineWidth
const outsideRadius = r + halfLineWidth
return !checkPointIsInSector(position, rx, ry, insideRadius, startAngle, endAngle, clockWise) &&
checkPointIsInSector(position, rx, ry, outsideRadius, startAngle, endAngle, clockWise)
},
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
})
}
}
export const sector = {
shape: {
rx: 0,
ry: 0,
r: 0,
startAngle: 0,
endAngle: 0,
clockWise: true
},
validator({
shape
}) {
const keys = ['rx', 'ry', 'r', 'startAngle', 'endAngle']
if (keys.find(key => typeof shape[key] !== 'number')) {
console.error('Sector shape configuration is abnormal!')
return false
}
return true
},
draw({
ctx
}, {
shape
}) {
ctx.beginPath()
const {
rx,
ry,
r,
startAngle,
endAngle,
clockWise
} = shape
ctx.arc(rx, ry, r > 0 ? r : 0.01, startAngle, endAngle, !clockWise)
ctx.lineTo(rx, ry)
ctx.closePath()
ctx.stroke()
ctx.fill()
// ctx.draw()
},
hoverCheck(position, {
shape
}) {
const {
rx,
ry,
r,
startAngle,
endAngle,
clockWise
} = shape
return checkPointIsInSector(position, rx, ry, r, startAngle, endAngle, clockWise)
},
setGraphCenter(e, {
shape,
style
}) {
const {
rx,
ry
} = shape
style.graphCenter = [rx, ry]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
rx,
ry
} = shape
this.attr('shape', {
rx: rx + movementX,
ry: ry + movementY
})
}
}
export const regPolygon = {
shape: {
rx: 0,
ry: 0,
r: 0,
side: 0
},
validator({
shape
}) {
const {
side
} = shape
const keys = ['rx', 'ry', 'r', 'side']
if (keys.find(key => typeof shape[key] !== 'number')) {
console.error('RegPolygon shape configuration is abnormal!')
return false
}
if (side < 3) {
console.error('RegPolygon at least trigon!')
return false
}
return true
},
draw({
ctx
}, {
shape,
cache
}) {
ctx.beginPath()
const {
rx,
ry,
r,
side
} = shape
if (!cache.points || cache.rx !== rx || cache.ry !== ry || cache.r !== r || cache.side !== side) {
const points = getRegularPolygonPoints(rx, ry, r, side)
Object.assign(cache, {
points,
rx,
ry,
r,
side
})
}
const {
points
} = cache
drawPolylinePath(ctx, points)
ctx.closePath()
ctx.stroke()
ctx.fill()
// ctx.draw()
},
hoverCheck(position, {
cache
}) {
let {
points
} = cache
return checkPointIsInPolygon(position, points)
},
setGraphCenter(e, {
shape,
style
}) {
const {
rx,
ry
} = shape
style.graphCenter = [rx, ry]
},
move({
movementX,
movementY
}, {
shape,
cache
}) {
const {
rx,
ry
} = shape
cache.rx += movementX
cache.ry += movementY
this.attr('shape', {
rx: rx + movementX,
ry: ry + movementY
})
cache.points = cache.points.map(([x, y]) => [x + movementX, y + movementY])
}
}
export const polyline = {
shape: {
points: [],
close: false
},
validator({
shape
}) {
const {
points
} = shape
if (!(points instanceof Array)) {
console.error('Polyline points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
style: {
lineWidth
}
}) {
ctx.beginPath()
let {
points,
close
} = shape
if (lineWidth === 1) points = eliminateBlur(points)
drawPolylinePath(ctx, points)
if (close) {
ctx.closePath()
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
// ctx.draw()
},
hoverCheck(position, {
shape,
style
}) {
const {
points,
close
} = shape
const {
lineWidth
} = style
if (close) {
return checkPointIsInPolygon(position, points)
} else {
return checkPointIsNearPolyline(position, points, lineWidth)
}
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
points
} = shape
const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: moveAfterPoints
})
}
}
export const smoothline = {
shape: {
points: [],
close: false
},
validator({
shape
}) {
const {
points
} = shape
if (!(points instanceof Array)) {
console.error('Smoothline points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
cache
}) {
const {
points,
close
} = shape
if (!cache.points || cache.points.toString() !== points.toString()) {
const bezierCurve = polylineToBezierCurve(points, close)
const hoverPoints = bezierCurveToPolyline(bezierCurve)
Object.assign(cache, {
points: deepClone(points, true),
bezierCurve,
hoverPoints
})
}
const {
bezierCurve
} = cache
ctx.beginPath()
drawBezierCurvePath(ctx, bezierCurve.slice(1), bezierCurve[0])
if (close) {
ctx.closePath()
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
// ctx.draw()
},
hoverCheck(position, {
cache,
shape,
style
}) {
const {
hoverPoints
} = cache
const {
close
} = shape
const {
lineWidth
} = style
if (close) {
return checkPointIsInPolygon(position, hoverPoints)
} else {
return checkPointIsNearPolyline(position, hoverPoints, lineWidth)
}
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape,
cache
}) {
const {
points
} = shape
const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY])
cache.points = moveAfterPoints
const [fx, fy] = cache.bezierCurve[0]
const curves = cache.bezierCurve.slice(1)
cache.bezierCurve = [
[fx + movementX, fy + movementY],
...curves.map(curve => curve.map(([x, y]) => [x + movementX, y + movementY]))
]
cache.hoverPoints = cache.hoverPoints.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: moveAfterPoints
})
}
}
export const bezierCurve = {
shape: {
points: [],
close: false
},
validator({
shape
}) {
const {
points
} = shape
if (!(points instanceof Array)) {
console.error('BezierCurve points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
cache
}) {
let {
points,
close
} = shape
if (!cache.points || cache.points.toString() !== points.toString()) {
const hoverPoints = bezierCurveToPolyline(points, 20)
Object.assign(cache, {
points: deepClone(points, true),
hoverPoints
})
}
ctx.beginPath()
drawBezierCurvePath(ctx, points.slice(1), points[0])
if (close) {
ctx.closePath()
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
// ctx.draw()
},
hoverCheck(position, {
cache,
shape,
style
}) {
const {
hoverPoints
} = cache
const {
close
} = shape
const {
lineWidth
} = style
if (close) {
return checkPointIsInPolygon(position, hoverPoints)
} else {
return checkPointIsNearPolyline(position, hoverPoints, lineWidth)
}
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape,
cache
}) {
const {
points
} = shape
const [fx, fy] = points[0]
const curves = points.slice(1)
const bezierCurve = [
[fx + movementX, fy + movementY],
...curves.map(curve => curve.map(([x, y]) => [x + movementX, y + movementY]))
]
cache.points = bezierCurve
cache.hoverPoints = cache.hoverPoints.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: bezierCurve
})
}
}
export const text = {
shape: {
content: '',
position: [],
x: 0,
y: 0,
rowGap: 0
},
validator({
shape,
style
}, ctx) {
const {
content,
position,
rowGap
} = shape
if (typeof content !== 'string') {
console.error('Text content should be a string!')
return false
}
if (!(position instanceof Array)) {
console.error('Text position should be an array!')
return false
}
if (typeof rowGap !== 'number') {
console.error('Text rowGap should be a number!')
return false
}
this.textWidth = 0
this.textHeight = 0
return true
},
measureSize(ctx, text) {
var _context = ctx,
fontSize = this.fontSize(),
metrics;
_context.save();
_context.font = ctx.font;
metrics = _context.measureText(text + "");
_context.restore();
return {
width: metrics.width,
height: fontSize,
};
},
draw({
ctx,
area
}, {
shape,
style
}) {
let {
content,
position,
maxWidth,
rowGap,
} = shape
let {
lineWidth
} = style;
const {
textBaseline,
font,
} = ctx
const [w, h] = area
const fontSize = parseInt(font.replace(/\D/g, ''))
let [x, y] = position
content = content.split('\n')
const rowNum = content.length
const lineHeight = fontSize + rowGap
const allHeight = rowNum * lineHeight - rowGap
let offset = 0
if (textBaseline === 'middle') {
offset = allHeight / 2
y += fontSize / 2
}
if (textBaseline === 'bottom') {
offset = allHeight
y += fontSize
}
position = new Array(rowNum).fill(0).map((foo, i) => [x, y + i * lineHeight - offset])
if (typeof maxWidth == 'undefined' || !maxWidth) maxWidth = w
// #ifdef H5
maxWidth = maxWidth * ctx.dpr
// #endif
let maxwi = []
ctx.beginPath()
content.forEach((text, i) => {
ctx.fillText(text, ...position[i], maxWidth)
if (lineWidth > 0) {
ctx.strokeText(text, ...position[i], maxWidth)
}
maxwi.push(ctx.measureText(text + "").width)
})
ctx.closePath()
this.textWidth = Math.max(...maxwi)
this.textHeight = allHeight
},
hoverCheck(position, {
cache,
shape,
style
}) {
const [x, y] = shape.position;
const {
textBaseline
} = style;
var w = this?.textWidth ?? 0;
var h = this?.textHeight ?? 0;
let isCheck = false;
if (textBaseline == 'top') {
if (position[0] >= x && position[0] <= x + w && position[1] >= y && position[1] <= y + h) {
isCheck = true;
}
} else if (textBaseline == 'bottom') {
if (position[0] >= x && position[0] <= x + w && position[1] >= y + h && position[1] <= y + h * 2) {
isCheck = true;
}
} else if (textBaseline == 'middle') {
if (position[0] >= x && position[0] <= x + w && position[1] >= y - h / 2 && position[1] <= y + h - h /
2) {
isCheck = true;
}
}
return isCheck;
},
setGraphCenter(e, {
shape,
style
}) {
const {
position
} = shape
style.graphCenter = [...position]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
position: [x, y]
} = shape
this.attr('shape', {
position: [x + movementX, y + movementY]
})
}
}
export const path = {
shape: {
points: [],
close: false
},
validator({
shape
}) {
const {
points
} = shape
if (!(points instanceof Array)) {
console.error('Polyline points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
style: {
lineWidth
}
}) {
ctx.beginPath()
let {
points,
close
} = shape
if (lineWidth === 1) points = eliminateBlur(points)
drawPolylinePath(ctx, points)
if (close) {
ctx.closePath()
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
ctx.draw()
},
hoverCheck(position, {
shape,
style
}) {
const {
points,
close
} = shape
const {
lineWidth
} = style
if (close) {
return checkPointIsInPolygon(position, points)
} else {
return checkPointIsNearPolyline(position, points, lineWidth)
}
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
points
} = shape
const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: moveAfterPoints
})
}
}
export const image = {
shape: {
x: 0,
y: 0,
w: 0,
h: 0,
sx: 0,
sy: 0,
src: ''
},
validator({
shape
}) {
const {
x,
y,
w,
h,
src
} = shape
if (typeof x !== 'number' || typeof y !== 'number' || typeof w !== 'number' || typeof h !== 'number' || !
src) {
console.error('image x,y,w,h,src必填。')
return false
}
return true
},
draw({
ctx,
cav
}, {
shape
}) {
let {
x,
y,
w,
h,
sx,
sy,
src
} = shape
let t = this;
// #ifdef MP-WEIXIN
//1加载中2加载完成3从未加载。
if (typeof this['isLoad'] == 'undefined' || this['isLoad'] == 3) {
this['isLoad'] = 1;
const bg = cav.createImage()
bg.onload = () => {
setTimeout(function() {
console.warn('tm-render:图片加载完成')
ctx.drawImage(bg, x, y, w, h)
t['isLoad'] = 2;
shape.src = bg
if(t?.load){
t.load();
}
}, 400)
}
bg.onerror = () => t['isLoad'] = 3
bg.src = src;
}
if (this['isLoad'] == 2) {
ctx.drawImage(src, x, y, w, h)
} else {
console.log('image loadding...');
}
// #endif
// #ifndef MP-WEIXIN
if(typeof this['isLoad'] =='undefined') this['isLoad'] = 3;
if(this['isLoad']===3){
this['isLoad'] = 1;
setTimeout(()=>{
t['isLoad'] = 2;
if(this?.load){
this.load();
}
},1200)
}
ctx.drawImage(src, x, y, w, h, sx, sy)
// #endif
},
hoverCheck(position, {
shape
}) {
let {
x,
y,
w,
h
} = shape
return checkPointIsInRect(position, x, y, w, h)
},
setGraphCenter(e, {
shape,
style
}) {
const {
x,
y,
w,
h
} = shape
style.graphCenter = [x + w / 2, y + h / 2]
},
move({
movementX,
movementY
}, {
shape
}) {
this.attr('shape', {
x: shape.x + movementX,
y: shape.y + movementY
})
}
}
export const star = {
shape: {
points: [],
close: false,
x: 0,
y: 0,
numPoints: 5, //星星的角数量
innerRadius: 40, //内部凹进去的比例
outerRadius: 70, //角向外凸出的比例。
},
validator({
shape
}) {
const {
points,
x,
y
} = shape
if (typeof x !== 'number' || typeof y !== 'number') {
console.error('Polyline points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
style: {
lineWidth
}
}) {
let context = ctx;
let {
points,
close,
x,
y,
numPoints,
innerRadius,
outerRadius
} = shape;
context.beginPath();
context.moveTo(x, y - outerRadius);
points.push([x, y - outerRadius])
for (var n = 1; n <= numPoints * 2; n++) {
var radius = n % 2 === 0 ? outerRadius : innerRadius;
var x2 = radius * Math.sin((n * Math.PI) / numPoints);
var y2 = -1 * radius * Math.cos((n * Math.PI) / numPoints);
context.lineTo(x2 + x, y2 + y);
points.push([x2 + x, y2 + y])
}
this.shape.points = points;
if (lineWidth === 1) points = eliminateBlur(points)
if (close) {
ctx.closePath()
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
// ctx.draw()
},
hoverCheck(position, {
shape,
style
}) {
const {
points,
close
} = shape
const {
lineWidth
} = style
if (close) {
return checkPointIsInPolygon(position, points)
} else {
return checkPointIsNearPolyline(position, points, lineWidth)
}
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
points
} = shape
const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: moveAfterPoints
})
}
}
export const arrow = {
shape: {
points: [],
close: true,
x: 0,
y: 0,
tension: 0, //弯曲程度。
pointerLength: 0, //箭头指针长度。
pointerWidth: 0, //箭头指针宽度。
pointerAtBeginning: false, //我们需要在两边画指针吗?默认值为 false。
pointerAtEnding: true, //结束端显示箭头。
hitPoints: [], //检测命中点。
},
validator({
shape
}) {
const {
points,
x,
y,
close,
tension,
pointerLength,
pointerWidth,
pointerAtBeginning,
pointerAtEnding
} = shape
if (typeof x !== 'number' || typeof y !== 'number') {
console.error('Polyline points should be an array!')
return false
}
return true
},
draw({
ctx
}, {
shape,
style: {
lineWidth
}
}) {
let context = ctx;
let {
points,
x,
y,
close,
tension,
pointerLength,
pointerWidth,
pointerAtBeginning,
pointerAtEnding
} = shape
let old_x = points[2] - points[0]
let old_y = points[3] - points[1]
points[0] = this.shape.x
points[1] = this.shape.y
points[2] = this.shape.x + old_x
points[3] = this.shape.y + old_y
var PI2 = Math.PI * 2;
var tp = points;
var fromTension = tension !== 0 && points.length > 4;
if (fromTension) {
if (close) {
tp = getTensionPointsClosed(points, tension);
} else {
tp = expandPoints(points, tension);
}
console.log(tp);
}
var length = pointerLength;
var n = points.length;
var dx, dy;
if (fromTension) {
const lp = [
tp[tp.length - 4],
tp[tp.length - 3],
tp[tp.length - 2],
tp[tp.length - 1],
points[n - 2],
points[n - 1],
];
const lastLength = calcLength(tp[tp.length - 4], tp[tp.length - 3], 'C', lp);
const previous = getPointOnQuadraticBezier(Math.min(1, 1 - length / lastLength), lp[0], lp[1], lp[2],
lp[3], lp[4], lp[5]);
dx = points[n - 2] - previous.x;
dy = points[n - 1] - previous.y;
} else {
dx = points[n - 2] - points[n - 4];
dy = points[n - 1] - points[n - 3];
}
var radians = (Math.atan2(dy, dx) + PI2) % PI2;
var width = pointerWidth;
this.shape.hitPoints = []
ctx.save();
ctx.beginPath();
ctx.moveTo(points[0], points[1]);
// #ifdef H5 || APP-VUE
ctx.lineTo(points[2], points[3]);
// #endif
// #ifdef MP
ctx.lineTo(points[2], points[3]);
// #endif
ctx.closePath();
if (pointerAtEnding) {
ctx.translate(points[n - 2], points[n - 1]);
ctx.rotate(radians);
// #ifdef H5 || APP-VUE
ctx.moveTo(points[2], points[3]);
ctx.lineTo(points[2], points[3] - width / 2);
ctx.lineTo(length + points[2], points[3]);
ctx.lineTo(points[2], width / 2 + points[3]);
// #endif
// #ifdef MP
ctx.moveTo(0, 0);
ctx.lineTo(-length, width / 2);
ctx.lineTo(-length, -width / 2);
// #endif
ctx.closePath();
ctx.restore();
this.shape.hitPoints.push([points[2], points[3] - width / 2]);
this.shape.hitPoints.push([length + points[2], points[3]]);
this.shape.hitPoints.push([points[2], width / 2 + points[3]]);
}
if (pointerAtBeginning) {
if (pointerAtBeginning) {
ctx.save();
}
ctx.translate(x, y);
if (fromTension) {
dx = (tp[0] + tp[2]) / 2 - points[0];
dy = (tp[1] + tp[3]) / 2 - points[1];
} else {
dx = points[2] - points[0];
dy = points[3] - points[1];
}
ctx.rotate((Math.atan2(-dy, -dx) + PI2) % PI2);
// #ifdef H5 || APP-VUE
ctx.moveTo(points[0], points[1]);
ctx.lineTo(points[0], points[1] - width / 2);
ctx.lineTo(-length + points[0], points[1]);
ctx.lineTo(points[0], width / 2 + points[1]);
// #endif
// #ifdef MP
ctx.moveTo(0, 0);
ctx.lineTo(-length, width / 2);
ctx.lineTo(-length, -width / 2);
// #endif
ctx.closePath();
ctx.restore();
}
if (close) {
ctx.fill()
ctx.stroke()
} else {
ctx.stroke()
}
},
hoverCheck(position, {
shape,
style
}) {
const {
points,
hitPoints,
close,
pointerLength,
pointerWidth
} = shape
const {
lineWidth
} = style
// if (close) {
// console.log( checkPointIsInPolygon(position, hitPoints));
// return checkPointIsInPolygon(position, hitPoints)
// } else {
// return checkPointIsNearPolyline(position, hitPoints, lineWidth)
// }
// #ifdef H5 || APP-VUE
return checkPointIsInRect(position, points[2], points[3] - pointerWidth / 2, pointerLength, pointerWidth)
// #endif
// #ifdef MP
return checkPointIsInRect(position, points[2] - pointerLength, points[3] - pointerWidth / 2, pointerLength,
pointerWidth)
// #endif
},
setGraphCenter(e, {
shape,
style
}) {
const {
points
} = shape
style.graphCenter = points[0]
},
move({
movementX,
movementY
}, {
shape
}) {
const {
points
} = shape
const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY])
this.attr('shape', {
points: moveAfterPoints
})
}
}
const graphs = new Map([
['rectRound', rectRound],
['arrow', arrow],
['star', star],
['image', image],
['path', path],
['circle', circle],
['ellipse', ellipse],
['rect', rect],
['ring', ring],
['arc', arc],
['sector', sector],
['regPolygon', regPolygon],
['polyline', polyline],
['smoothline', smoothline],
['bezierCurve', bezierCurve],
['text', text]
])
export default graphs
/**
* @description Extend new graph
* @param {String} name Name of Graph
* @param {Object} config Configuration of Graph
* @return {Undefined} Void
*/
export function extendNewGraph(name, config) {
if (!name || !config) {
console.error('ExtendNewGraph Missing Parameters!')
return
}
if (!config.shape) {
console.error('Required attribute of shape to extendNewGraph!')
return
}
if (!config.validator) {
console.error('Required function of validator to extendNewGraph!')
return
}
if (!config.draw) {
console.error('Required function of draw to extendNewGraph!')
return
}
graphs.set(name, config)
}