| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- import { doUpdate } from '../class/updater.class'
- import { gaugeConfig } from '../config/gauge'
- import { getCircleRadianPoint } from '@jiaminghi/c-render/lib/plugin/util'
- import { deepMerge, initNeedSeries, radianToAngle } from '../util'
- import { getRgbaValue } from '@jiaminghi/color'
- export function gauge (chart, option = {}) {
- let { series } = option
- if (!series) series = []
- let gauges = initNeedSeries(series, gaugeConfig, 'gauge')
- gauges = calcGaugesCenter(gauges, chart)
- gauges = calcGaugesRadius(gauges, chart)
- gauges = calcGaugesDataRadiusAndLineWidth(gauges, chart)
- gauges = calcGaugesDataAngles(gauges, chart)
- gauges = calcGaugesDataGradient(gauges, chart)
- gauges = calcGaugesAxisTickPosition(gauges, chart)
- gauges = calcGaugesLabelPositionAndAlign(gauges, chart)
- gauges = calcGaugesLabelData(gauges, chart)
- gauges = calcGaugesDetailsPosition(gauges, chart)
- gauges = calcGaugesDetailsContent(gauges, chart)
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugeAxisTick',
- getGraphConfig: getAxisTickConfig
- })
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugeAxisLabel',
- getGraphConfig: getAxisLabelConfig
- })
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugeBackgroundArc',
- getGraphConfig: getBackgroundArcConfig,
- getStartGraphConfig: getStartBackgroundArcConfig
- })
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugeArc',
- getGraphConfig: getArcConfig,
- getStartGraphConfig: getStartArcConfig,
- beforeChange: beforeChangeArc
- })
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugePointer',
- getGraphConfig: getPointerConfig,
- getStartGraphConfig: getStartPointerConfig
- })
- doUpdate({
- chart,
- series: gauges,
- key: 'gaugeDetails',
- getGraphConfig: getDetailsConfig
- })
- }
- function calcGaugesCenter (gauges, chart) {
- const { area } = chart.render
- gauges.forEach(gaugeItem => {
- let { center } = gaugeItem
- center = center.map((pos, i) => {
- if (typeof pos === 'number') return pos
- return parseInt(pos) / 100 * area[i]
- })
- gaugeItem.center = center
- })
- return gauges
- }
- function calcGaugesRadius (gauges, chart) {
- const { area } = chart.render
- const maxRadius = Math.min(...area) / 2
- gauges.forEach(gaugeItem => {
- let { radius } = gaugeItem
- if (typeof radius !== 'number') {
- radius = parseInt(radius) / 100 * maxRadius
- }
- gaugeItem.radius = radius
- })
- return gauges
- }
- function calcGaugesDataRadiusAndLineWidth (gauges, chart) {
- const { area } = chart.render
- const maxRadius = Math.min(...area) / 2
- gauges.forEach(gaugeItem => {
- const { radius, data, arcLineWidth } = gaugeItem
- data.forEach(item => {
- let { radius: arcRadius, lineWidth } = item
- if (!arcRadius) arcRadius = radius
- if (typeof arcRadius !== 'number') arcRadius = parseInt(arcRadius) / 100 * maxRadius
- item.radius = arcRadius
- if (!lineWidth) lineWidth = arcLineWidth
- item.lineWidth = lineWidth
- })
- })
- return gauges
- }
- function calcGaugesDataAngles (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { startAngle, endAngle, data, min, max } = gaugeItem
-
- const angleMinus = endAngle - startAngle
- const valueMinus = max - min
- data.forEach(item => {
- const { value } = item
- const itemAngle = Math.abs((value - min) / valueMinus * angleMinus)
- item.startAngle = startAngle
- item.endAngle = startAngle + itemAngle
- })
- })
- return gauges
- }
- function calcGaugesDataGradient (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { data } = gaugeItem
- data.forEach(item => {
- let { color, gradient } = item
- if (!gradient || !gradient.length) gradient = color
- if (!(gradient instanceof Array)) gradient = [gradient]
- item.gradient = gradient
- })
- })
- return gauges
- }
- function calcGaugesAxisTickPosition (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { startAngle, endAngle, splitNum, center, radius, arcLineWidth, axisTick } = gaugeItem
- const { tickLength, style: { lineWidth } } = axisTick
- const angles = endAngle - startAngle
- const outerRadius = radius - (arcLineWidth / 2)
- const innerRadius = outerRadius - tickLength
- const angleGap = angles / (splitNum - 1)
- const arcLength = 2 * Math.PI * radius * angles / (Math.PI * 2)
- const offset = Math.ceil(lineWidth / 2) / arcLength * angles
- gaugeItem.tickAngles = []
- gaugeItem.tickInnerRadius = []
- gaugeItem.tickPosition = new Array(splitNum).fill(0)
- .map((foo, i) => {
- let angle = startAngle + angleGap * i
- if (i === 0) angle += offset
- if (i === splitNum - 1) angle -= offset
- gaugeItem.tickAngles[i] = angle
- gaugeItem.tickInnerRadius[i] = innerRadius
- return [
- getCircleRadianPoint(...center, outerRadius, angle),
- getCircleRadianPoint(...center, innerRadius, angle)
- ]
- })
- })
- return gauges
- }
- function calcGaugesLabelPositionAndAlign (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { center, tickInnerRadius, tickAngles, axisLabel: { labelGap } } = gaugeItem
- const position = tickAngles.map((angle, i) => getCircleRadianPoint(
- ...center,
- tickInnerRadius[i] - labelGap,
- tickAngles[i]
- ))
- const align = position.map(([x, y]) => ({
- textAlign: x > center[0] ? 'right' : 'left',
- textBaseline: y > center[1] ? 'bottom' : 'top'
- }))
- gaugeItem.labelPosition = position
- gaugeItem.labelAlign = align
- })
- return gauges
- }
- function calcGaugesLabelData (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { axisLabel, min, max, splitNum } = gaugeItem
- let { data, formatter } = axisLabel
- const valueGap = (max - min) / (splitNum - 1)
- const value = new Array(splitNum).fill(0).map((foo, i) => parseInt(min + valueGap * i))
- const formatterType = typeof formatter
- data = deepMerge(value, data).map((v, i) => {
- let label = v
- if (formatterType === 'string') {
- label = formatter.replace('{value}', v)
- }
- if (formatterType === 'function') {
- label = formatter({ value: v, index: i })
- }
- return label
- })
- axisLabel.data = data
- })
- return gauges
- }
- function calcGaugesDetailsPosition (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { data, details, center } = gaugeItem
- const { position, offset } = details
- const detailsPosition = data.map(({ startAngle, endAngle, radius }) => {
- let point = null
- if (position === 'center') {
- point = center
- } else if (position === 'start') {
- point = getCircleRadianPoint(...center, radius, startAngle)
- } else if (position === 'end') {
- point = getCircleRadianPoint(...center, radius, endAngle)
- }
- return getOffsetedPoint(point, offset)
- })
- gaugeItem.detailsPosition = detailsPosition
- })
- return gauges
- }
- function calcGaugesDetailsContent (gauges, chart) {
- gauges.forEach(gaugeItem => {
- const { data, details } = gaugeItem
- const { formatter } = details
- const formatterType = typeof formatter
- const contents = data.map(dataItem => {
- let content = dataItem.value
- if (formatterType === 'string') {
- content = formatter.replace('{value}', '{nt}')
- content = content.replace('{name}', dataItem.name)
- }
- if (formatterType === 'function') content = formatter(dataItem)
- return content.toString()
- })
- gaugeItem.detailsContent = contents
- })
- return gauges
- }
- function getOffsetedPoint ([x, y], [ox, oy]) {
- return [x + ox, y + oy]
- }
- function getAxisTickConfig (gaugeItem) {
- const { tickPosition, animationCurve, animationFrame, rLevel } = gaugeItem
- return tickPosition.map((foo, i) => ({
- name: 'polyline',
- index: rLevel,
- visible: gaugeItem.axisTick.show,
- animationCurve,
- animationFrame,
- shape: getAxisTickShape(gaugeItem, i),
- style: getAxisTickStyle(gaugeItem, i)
- }))
- }
- function getAxisTickShape (gaugeItem, i) {
- const { tickPosition } = gaugeItem
- return { points: tickPosition[i] }
- }
- function getAxisTickStyle (gaugeItem, i) {
- const { axisTick: { style } } = gaugeItem
- return style
- }
- function getAxisLabelConfig (gaugeItem) {
- const { labelPosition, animationCurve, animationFrame, rLevel } = gaugeItem
- return labelPosition.map((foo, i) => ({
- name: 'text',
- index: rLevel,
- visible: gaugeItem.axisLabel.show,
- animationCurve,
- animationFrame,
- shape: getAxisLabelShape(gaugeItem, i),
- style: getAxisLabelStyle(gaugeItem, i)
- }))
- }
- function getAxisLabelShape (gaugeItem, i) {
- const { labelPosition, axisLabel: { data } } = gaugeItem
- return {
- content: data[i].toString(),
- position: labelPosition[i]
- }
- }
- function getAxisLabelStyle (gaugeItem, i) {
- const { labelAlign, axisLabel } = gaugeItem
- const { style } = axisLabel
- return deepMerge({ ...labelAlign[i] }, style)
- }
- function getBackgroundArcConfig (gaugeItem) {
- const { animationCurve, animationFrame, rLevel } = gaugeItem
- return [{
- name: 'arc',
- index: rLevel,
- visible: gaugeItem.backgroundArc.show,
- animationCurve,
- animationFrame,
- shape: getGaugeBackgroundArcShape(gaugeItem),
- style: getGaugeBackgroundArcStyle(gaugeItem)
- }]
- }
- function getGaugeBackgroundArcShape (gaugeItem) {
- let { startAngle, endAngle, center, radius } = gaugeItem
- return {
- rx: center[0],
- ry: center[1],
- r: radius,
- startAngle,
- endAngle
- }
- }
- function getGaugeBackgroundArcStyle (gaugeItem) {
- const { backgroundArc, arcLineWidth } = gaugeItem
- const { style } = backgroundArc
- return deepMerge({ lineWidth: arcLineWidth }, style)
- }
- function getStartBackgroundArcConfig (gaugeItem) {
- const config = getBackgroundArcConfig(gaugeItem)[0]
- const shape = { ...config.shape }
- shape.endAngle = config.shape.startAngle
- config.shape = shape
- return [config]
- }
- function getArcConfig (gaugeItem) {
- const { data, animationCurve, animationFrame, rLevel } = gaugeItem
- return data.map((foo, i) => ({
- name: 'agArc',
- index: rLevel,
- animationCurve,
- animationFrame,
- shape: getGaugeArcShape(gaugeItem, i),
- style: getGaugeArcStyle(gaugeItem, i)
- }))
- }
- function getGaugeArcShape (gaugeItem, i) {
- let { data, center, endAngle: gradientEndAngle } = gaugeItem
- const { radius, startAngle, endAngle, localGradient } = data[i]
- if (localGradient) gradientEndAngle = endAngle
- return {
- rx: center[0],
- ry: center[1],
- r: radius,
- startAngle,
- endAngle,
- gradientEndAngle
- }
- }
- function getGaugeArcStyle (gaugeItem, i) {
- const { data, dataItemStyle } = gaugeItem
- let { lineWidth, gradient } = data[i]
- gradient = gradient.map(c => getRgbaValue(c))
- return deepMerge({ lineWidth, gradient }, dataItemStyle)
- }
- function getStartArcConfig (gaugeItem) {
- const configs = getArcConfig(gaugeItem)
- configs.map(config => {
- const shape = { ...config.shape }
- shape.endAngle = config.shape.startAngle
- config.shape = shape
- })
- return configs
- }
- function beforeChangeArc (graph, config) {
- const graphGradient = graph.style.gradient
- const cacheNum = graphGradient.length
- const needNum = config.style.gradient.length
- if (cacheNum > needNum) {
- graphGradient.splice(needNum)
- } else {
- const last = graphGradient.slice(-1)[0]
- graphGradient.push(...new Array(needNum - cacheNum).fill(0).map(foo => [...last]))
- }
- }
- function getPointerConfig (gaugeItem) {
- const { animationCurve, animationFrame, center, rLevel } = gaugeItem
- return [{
- name: 'polyline',
- index: rLevel,
- visible: gaugeItem.pointer.show,
- animationCurve,
- animationFrame,
- shape: getPointerShape(gaugeItem),
- style: getPointerStyle(gaugeItem),
- setGraphCenter (foo, graph) { graph.style.graphCenter = center }
- }]
- }
- function getPointerShape (gaugeItem) {
- const { center } = gaugeItem
- return {
- points: getPointerPoints(center),
- close: true
- }
- }
- function getPointerStyle (gaugeItem) {
- const { startAngle, endAngle, min, max, data, pointer, center } = gaugeItem
- const { valueIndex, style } = pointer
- let value = data[valueIndex] ? data[valueIndex].value : 0
- const angle = (value - min) / (max - min) * (endAngle - startAngle) + startAngle + Math.PI / 2
- return deepMerge({ rotate: radianToAngle(angle), scale: [1, 1], graphCenter: center }, style)
- }
- function getPointerPoints ([x, y]) {
- const point1 = [x, y - 40]
- const point2 = [x + 5, y]
- const point3 = [x, y + 10]
- const point4 = [x - 5, y]
- return [point1, point2, point3, point4]
- }
- function getStartPointerConfig (gaugeItem) {
- const { startAngle } = gaugeItem
- const config = getPointerConfig(gaugeItem)[0]
- config.style.rotate = radianToAngle(startAngle + Math.PI / 2)
- return [config]
- }
- function getDetailsConfig (gaugeItem) {
- const { detailsPosition, animationCurve, animationFrame, rLevel } = gaugeItem
- const visible = gaugeItem.details.show
- return detailsPosition.map((foo, i) => ({
- name: 'numberText',
- index: rLevel,
- visible,
- animationCurve,
- animationFrame,
- shape: getDetailsShape(gaugeItem, i),
- style: getDetailsStyle(gaugeItem, i)
- }))
- }
- function getDetailsShape (gaugeItem, i) {
- const { detailsPosition, detailsContent, data, details } = gaugeItem
- const position = detailsPosition[i]
- const content = detailsContent[i]
- const dataValue = data[i].value
- const toFixed = details.valueToFixed
- return {
- number: [dataValue],
- content,
- position,
- toFixed
- }
- }
- function getDetailsStyle (gaugeItem, i) {
- const { details, data } = gaugeItem
- const { style } = details
- const { color } = data[i]
- return deepMerge({ fill: color }, style)
- }
|