@jiaminghi/charts
Version:
Lightweight charting
394 lines (265 loc) • 8.79 kB
JavaScript
import { doUpdate } from '../class/updater.class'
import { radarAxisConfig } from '../config/index'
import { deepClone, getCircleRadianPoint } from '@jiaminghi/c-render/lib/plugin/util'
import { deepMerge, getPointToLineDistance } from '../util'
export function radarAxis (chart, option = {}) {
let { radar } = option
let radarAxis = []
if (radar) {
radarAxis = mergeRadarAxisDefaultConfig(radar)
radarAxis = calcRadarAxisCenter(radarAxis, chart)
radarAxis = calcRadarAxisRingRadius(radarAxis, chart)
radarAxis = calcRadarAxisLinePosition(radarAxis)
radarAxis = calcRadarAxisAreaRadius(radarAxis)
radarAxis = calcRadarAxisLabelPosition(radarAxis)
radarAxis = [radarAxis]
}
let radarAxisForUpdate = radarAxis
if (radarAxis.length && !radarAxis[0].show) radarAxisForUpdate = []
doUpdate({
chart,
series: radarAxisForUpdate,
key: 'radarAxisSplitArea',
getGraphConfig: getSplitAreaConfig,
beforeUpdate: beforeUpdateSplitArea,
beforeChange: beforeChangeSplitArea
})
doUpdate({
chart,
series: radarAxisForUpdate,
key: 'radarAxisSplitLine',
getGraphConfig: getSplitLineConfig,
beforeUpdate: beforeUpdateSplitLine,
beforeChange: beforeChangeSplitLine
})
doUpdate({
chart,
series: radarAxisForUpdate,
key: 'radarAxisLine',
getGraphConfig: getAxisLineConfig,
})
doUpdate({
chart,
series: radarAxisForUpdate,
key: 'radarAxisLable',
getGraphConfig: getAxisLabelConfig,
})
chart.radarAxis = radarAxis[0]
}
function mergeRadarAxisDefaultConfig (radar) {
return deepMerge(deepClone(radarAxisConfig), radar)
}
function calcRadarAxisCenter (radarAxis, chart) {
const { area } = chart.render
const { center } = radarAxis
radarAxis.centerPos = center.map((v, i) => {
if (typeof v === 'number') return v
return parseInt(v) / 100 * area[i]
})
return radarAxis
}
function calcRadarAxisRingRadius (radarAxis, chart) {
const { area } = chart.render
let { splitNum, radius } = radarAxis
const maxRadius = Math.min(...area) / 2
if (typeof radius !== 'number') radius = parseInt(radius) / 100 * maxRadius
const splitGap = radius / splitNum
radarAxis.ringRadius = new Array(splitNum).fill(0)
.map((foo, i) => splitGap * (i + 1))
radarAxis.radius = radius
return radarAxis
}
function calcRadarAxisLinePosition (radarAxis) {
const { indicator, centerPos, radius, startAngle } = radarAxis
const fullAngle = Math.PI * 2
const indicatorNum = indicator.length
const indicatorGap = fullAngle / indicatorNum
const angles = new Array(indicatorNum).fill(0)
.map((foo, i) => indicatorGap * i + startAngle)
radarAxis.axisLineAngles = angles
radarAxis.axisLinePosition = angles.map(g => {
return getCircleRadianPoint(...centerPos, radius, g)
})
return radarAxis
}
function calcRadarAxisAreaRadius (radarAxis) {
const { ringRadius } = radarAxis
const subRadius = ringRadius[0] / 2
radarAxis.areaRadius = ringRadius.map(r => r - subRadius)
return radarAxis
}
function calcRadarAxisLabelPosition (radarAxis) {
let { axisLineAngles, centerPos, radius, axisLabel } = radarAxis
radius += axisLabel.labelGap
radarAxis.axisLabelPosition = axisLineAngles.map(angle =>
getCircleRadianPoint(...centerPos, radius, angle))
return radarAxis
}
function getSplitAreaConfig (radarAxis) {
const { areaRadius, polygon, animationCurve, animationFrame, rLevel } = radarAxis
const name = polygon ? 'regPolygon' : 'ring'
return areaRadius.map((foo, i) => ({
name,
index: rLevel,
visible: radarAxis.splitArea.show,
animationCurve,
animationFrame,
shape: getSplitAreaShape(radarAxis, i),
style: getSplitAreaStyle(radarAxis, i)
}))
}
function getSplitAreaShape (radarAxis, i) {
const { polygon, areaRadius, indicator, centerPos } = radarAxis
const indicatorNum = indicator.length
let shape = {
rx: centerPos[0],
ry: centerPos[1],
r: areaRadius[i]
}
if (polygon) shape.side = indicatorNum
return shape
}
function getSplitAreaStyle (radarAxis, i) {
const { splitArea, ringRadius, axisLineAngles, polygon, centerPos } = radarAxis
let { color, style } = splitArea
style = {
fill: 'rgba(0, 0, 0, 0)',
...style
}
let lineWidth = ringRadius[0] - 0
if (polygon) {
const point1 = getCircleRadianPoint(...centerPos, ringRadius[0], axisLineAngles[0])
const point2 = getCircleRadianPoint(...centerPos, ringRadius[0], axisLineAngles[1])
lineWidth = getPointToLineDistance(centerPos, point1, point2)
}
style = deepMerge(deepClone(style, true), { lineWidth })
if (!color.length) return style
const colorNum = color.length
return deepMerge(style, { stroke: color[i % colorNum] })
}
function beforeUpdateSplitArea (graphs, radarAxis, i, updater) {
const cache = graphs[i]
if (!cache) return
const { render } = updater.chart
const { polygon } = radarAxis
const { name } = cache[0]
const currentName = polygon ? 'regPolygon' : 'ring'
const delAll = currentName !== name
if (!delAll) return
cache.forEach(g => render.delGraph(g))
graphs[i] = null
}
function beforeChangeSplitArea (graph, config) {
const side = config.shape.side
if (typeof side !== 'number') return
graph.shape.side = side
}
function getSplitLineConfig (radarAxis) {
const { ringRadius, polygon, animationCurve, animationFrame, rLevel } = radarAxis
const name = polygon ? 'regPolygon' : 'ring'
return ringRadius.map((foo, i) => ({
name,
index: rLevel,
animationCurve,
animationFrame,
visible: radarAxis.splitLine.show,
shape: getSplitLineShape(radarAxis, i),
style: getSplitLineStyle(radarAxis, i)
}))
}
function getSplitLineShape (radarAxis, i) {
const { ringRadius, centerPos, indicator, polygon } = radarAxis
const shape = {
rx: centerPos[0],
ry: centerPos[1],
r: ringRadius[i]
}
const indicatorNum = indicator.length
if (polygon) shape.side = indicatorNum
return shape
}
function getSplitLineStyle (radarAxis, i) {
const { splitLine } = radarAxis
let { color, style } = splitLine
style = {
fill: 'rgba(0, 0, 0, 0)',
...style
}
if (!color.length) return style
const colorNum = color.length
return deepMerge(style, { stroke: color[i % colorNum] })
}
function beforeUpdateSplitLine (graphs, radarAxis, i, updater) {
const cache = graphs[i]
if (!cache) return
const { render } = updater.chart
const { polygon } = radarAxis
const { name } = cache[0]
const currenName = polygon ? 'regPolygon' : 'ring'
const delAll = currenName !== name
if (!delAll) return
cache.forEach(g => render.delGraph(g))
graphs[i] = null
}
function beforeChangeSplitLine (graph, config) {
const side = config.shape.side
if (typeof side !== 'number') return
graph.shape.side = side
}
function getAxisLineConfig (radarAxis) {
const { axisLinePosition, animationCurve, animationFrame, rLevel } = radarAxis
return axisLinePosition.map((foo, i) => ({
name: 'polyline',
index: rLevel,
visible: radarAxis.axisLine.show,
animationCurve,
animationFrame,
shape: getAxisLineShape(radarAxis, i),
style: getAxisLineStyle(radarAxis, i)
}))
}
function getAxisLineShape (radarAxis, i) {
const { centerPos, axisLinePosition } = radarAxis
const points = [centerPos, axisLinePosition[i]]
return { points }
}
function getAxisLineStyle (radarAxis, i) {
const { axisLine } = radarAxis
const { color, style } = axisLine
if (!color.length) return style
const colorNum = color.length
return deepMerge(style, { stroke: color[i % colorNum] })
}
function getAxisLabelConfig (radarAxis) {
const { axisLabelPosition, animationCurve, animationFrame, rLevel } = radarAxis
return axisLabelPosition.map((foo, i) => ({
name: 'text',
index: rLevel,
visible: radarAxis.axisLabel.show,
animationCurve,
animationFrame,
shape: getAxisLableShape(radarAxis, i),
style: getAxisLableStyle(radarAxis, i)
}))
}
function getAxisLableShape (radarAxis, i) {
const { axisLabelPosition, indicator } = radarAxis
return {
content: indicator[i].name,
position: axisLabelPosition[i]
}
}
function getAxisLableStyle (radarAxis, i) {
const { axisLabel, centerPos: [x, y], axisLabelPosition } = radarAxis
let { color, style } = axisLabel
const [labelXpos, labelYPos] = axisLabelPosition[i]
const textAlign = labelXpos > x ? 'left' : 'right'
const textBaseline = labelYPos > y ? 'top' : 'bottom'
style = deepMerge({
textAlign,
textBaseline
}, style)
if (!color.length) return style
const colorNum = color.length
return deepMerge(style, { fill: color[i % colorNum] })
}