@jiaminghi/charts
Version:
Lightweight charting
287 lines (202 loc) • 6.33 kB
JavaScript
import { doUpdate } from '../class/updater.class'
import { radarConfig } from '../config/index'
import { getCircleRadianPoint } from '@jiaminghi/c-render/lib/plugin/util'
import { getColorFromRgbValue, getRgbaValue } from '@jiaminghi/color'
import { deepMerge, initNeedSeries } from '../util'
export function radar (chart, option = {}) {
let { series } = option
if (!series) series = []
let radars = initNeedSeries(series, radarConfig, 'radar')
radars = calcRadarPosition(radars, chart)
radars = calcRadarLabelPosition(radars, chart)
radars = calcRadarLabelAlign(radars, chart)
doUpdate({
chart,
series: radars,
key: 'radar',
getGraphConfig: getRadarConfig,
getStartGraphConfig: getStartRadarConfig,
beforeChange: beforeChangeRadar
})
doUpdate({
chart,
series: radars,
key: 'radarPoint',
getGraphConfig: getPointConfig,
getStartGraphConfig: getStartPointConfig,
})
doUpdate({
chart,
series: radars,
key: 'radarLabel',
getGraphConfig: getLabelConfig
})
}
function calcRadarPosition (radars, chart) {
const { radarAxis } = chart
if (!radarAxis) return []
const { indicator, axisLineAngles, radius, centerPos } = radarAxis
radars.forEach(radarItem => {
const { data } = radarItem
radarItem.dataRadius = []
radarItem.radarPosition = indicator.map(({ max, min }, i) => {
let v = data[i]
if (typeof max !== 'number') max = v
if (typeof min !== 'number') min = 0
if (typeof v !== 'number') v = min
const dataRadius = (v - min) / (max - min) * radius
radarItem.dataRadius[i] = dataRadius
return getCircleRadianPoint(...centerPos, dataRadius, axisLineAngles[i])
})
})
return radars
}
function calcRadarLabelPosition (radars, chart) {
const { radarAxis } = chart
if (!radarAxis) return []
const { centerPos, axisLineAngles } = radarAxis
radars.forEach(radarItem => {
const { dataRadius, label } = radarItem
const { labelGap } = label
radarItem.labelPosition = dataRadius.map((r, i) => {
return getCircleRadianPoint(...centerPos, r + labelGap, axisLineAngles[i])
})
})
return radars
}
function calcRadarLabelAlign (radars, chart) {
const { radarAxis } = chart
if (!radarAxis) return []
const { centerPos: [x, y] } = radarAxis
radars.forEach(radarItem => {
const { labelPosition } = radarItem
const labelAlign = labelPosition.map(([lx, ly]) => {
const textAlign = lx > x ? 'left' : 'right'
const textBaseline = ly > y ? 'top' : 'bottom'
return {
textAlign,
textBaseline
}
})
radarItem.labelAlign = labelAlign
})
return radars
}
function getRadarConfig (radarItem) {
const { animationCurve, animationFrame, rLevel } = radarItem
return [{
name: 'polyline',
index: rLevel,
animationCurve,
animationFrame,
shape: getRadarShape(radarItem),
style: getRadarStyle(radarItem)
}]
}
function getStartRadarConfig (radarItem, updater) {
const { radarAxis: { centerPos } } = updater.chart
const config = getRadarConfig(radarItem)[0]
const pointNum = config.shape.points.length
const points = new Array(pointNum).fill(0).map(foo => [...centerPos])
config.shape.points = points
return [config]
}
function getRadarShape (radarItem) {
const { radarPosition } = radarItem
return {
points: radarPosition,
close: true
}
}
function getRadarStyle(radarItem) {
const { radarStyle, color } = radarItem
const colorRgbaValue = getRgbaValue(color)
colorRgbaValue[3] = 0.5
const radarDefaultColor = {
stroke: color,
fill: getColorFromRgbValue(colorRgbaValue)
}
return deepMerge(radarDefaultColor, radarStyle)
}
function beforeChangeRadar (graph, { shape }) {
const graphPoints = graph.shape.points
const graphPointsNum = graphPoints.length
const pointsNum = shape.points.length
if (pointsNum > graphPointsNum) {
const lastPoint = graphPoints.slice(-1)[0]
const newAddPoints = new Array(pointsNum - graphPointsNum)
.fill(0).map(foo => ([...lastPoint]))
graphPoints.push(...newAddPoints)
} else if (pointsNum < graphPointsNum) {
graphPoints.splice(pointsNum)
}
}
function getPointConfig (radarItem) {
const { radarPosition, animationCurve, animationFrame, rLevel } = radarItem
return radarPosition.map((foo, i) => ({
name: 'circle',
index: rLevel,
animationCurve,
animationFrame,
visible: radarItem.point.show,
shape: getPointShape(radarItem, i),
style: getPointStyle(radarItem, i),
}))
}
function getStartPointConfig (radarItem) {
const configs = getPointConfig(radarItem)
configs.forEach(config => config.shape.r = 0.01)
return configs
}
function getPointShape (radarItem, i) {
const { radarPosition, point } = radarItem
const { radius } = point
const position = radarPosition[i]
return {
rx: position[0],
ry: position[1],
r: radius
}
}
function getPointStyle (radarItem, i) {
const { point, color } = radarItem
const { style } = point
return deepMerge({ stroke: color }, style)
}
function getLabelConfig (radarItem) {
const { labelPosition, animationCurve, animationFrame, rLevel } = radarItem
return labelPosition.map((foo, i) => ({
name: 'text',
index: rLevel,
visible: radarItem.label.show,
animationCurve,
animationFrame,
shape: getLabelShape(radarItem, i),
style: getLabelStyle(radarItem, i)
}))
}
function getLabelShape (radarItem, i) {
const { labelPosition, label, data } = radarItem
const { offset, formatter } = label
const position = mergePointOffset(labelPosition[i], offset)
let labelText = data[i] ? data[i].toString() : '0'
const formatterType = typeof formatter
if (formatterType === 'string') labelText = formatter.replace('{value}', labelText)
if (formatterType === 'function') labelText = formatter(labelText)
return {
content: labelText,
position
}
}
function mergePointOffset ([x, y], [ox, oy]) {
return [x + ox, y + oy]
}
function getLabelStyle (radarItem, i) {
const { label, color, labelAlign } = radarItem
const { style } = label
const defaultColorAndAlign = {
fill: color,
...labelAlign[i]
}
return deepMerge(defaultColorAndAlign, style)
}