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

1 year ago
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)
}