| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 |
- import beziercurve from '@jiaminghi/bezier-curve'
- 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()
- },
- 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()
- },
- 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()
- },
- 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 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()
- },
- 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()
- },
- 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()
- },
- 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()
- },
- 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()
- }
- },
- 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()
- }
- },
- 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()
- }
- },
- 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: [],
- maxWidth: undefined,
- rowGap: 0
- },
- validator ({ shape }) {
- 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
- }
- return true
- },
- draw ({ ctx }, { shape }) {
- let { content, position, maxWidth, rowGap } = shape
- const { textBaseline, font } = ctx
- 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])
- ctx.beginPath()
- content.forEach((text, i) => {
- ctx.fillText(text, ...position[i], maxWidth)
- ctx.strokeText(text, ...position[i], maxWidth)
- })
- ctx.closePath()
- },
- hoverCheck (position, { shape, style }) {
- return false
- },
- 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]
- })
- }
- }
- const graphs = new Map([
- ['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)
- }
|