import { itemPoint } from '../../constants'
import { getFormated } from '../../utils'
import { isArray } from 'utils-lite'
const DEFAULT_MA = [5, 10, 20, 30]
const DEFAULT_K_NAME = '日K'
const DEFAULT_DOWN_COLOR = '#ec0000'
const DEFAULT_UP_COLOR = '#00da3c'
const DEFAULT_START = 50
const DEFAULT_END = 100
const SHOW_FALSE = { show: false }
function getCandleLegend (args) {
const { showMA, MA, legendName, labelMap } = args
let data = [DEFAULT_K_NAME]
if (showMA) data = data.concat(MA.map(v => `MA${v}`))
if (labelMap) data = data.map(v => labelMap[v] == null ? v : labelMap[v])
return {
data,
formatter (name) {
return legendName[name] != null ? legendName[name] : name
}
}
}
function getCandleTooltip (args) {
const { metrics, dataType, digit, labelMap } = args
return {
trigger: 'axis',
axisPointer: { type: 'cross' },
position (pos, params, el, elRect, size) {
const result = { top: 10 }
const side = pos[0] < size.viewSize[0] / 2 ? 'right' : 'left'
result[side] = 60
return result
},
formatter (options) {
const tpl = []
tpl.push(`${options[0].axisValue}
`)
options.forEach(option => {
const { data, seriesName, componentSubType, color } = option
const name = labelMap[seriesName] == null ? seriesName : labelMap[seriesName]
tpl.push(`${itemPoint(color)} ${name}: `)
if (componentSubType === 'candlestick') {
tpl.push('
')
metrics.slice(0, 4).forEach((m, i) => {
const name = labelMap[m] != null ? labelMap[m] : m
const val = getFormated(data[i + 1], dataType, digit)
tpl.push(`- ${name}: ${val}
`)
})
} else if (componentSubType === 'line') {
const val = getFormated(data, dataType, digit)
tpl.push(`${val}
`)
} else if (componentSubType === 'bar') {
const val = getFormated(data[1], dataType, digit)
tpl.push(`${val}
`)
}
})
return tpl.join('')
}
}
}
function getCandleVisualMap (args) {
const { downColor, upColor, MA, showMA } = args
return {
show: false,
seriesIndex: showMA ? 1 + MA.length : 1,
dimension: 2,
pieces: [
{ value: 1, color: downColor },
{ value: -1, color: upColor }
]
}
}
function getCandleGrid (args) {
const { showVol } = args
return [
{
left: '10%',
right: '8%',
top: '10%',
height: showVol ? '50%' : '65%',
containLabel: false
},
{
left: '10%',
right: '8%',
top: '65%',
height: '16%',
containLabel: false
}
]
}
function getCandleXAxis (args) {
const { dims: data } = args
const type = 'category'
const scale = true
const boundaryGap = false
const splitLine = SHOW_FALSE
const axisLine = { onZero: false }
const axisTick = SHOW_FALSE
const axisLabel = SHOW_FALSE
const min = 'dataMin'
const max = 'dataMax'
const gridIndex = 1
return [
{ type, data, scale, boundaryGap, axisLine, splitLine, min, max },
{ type, gridIndex, data, scale, boundaryGap, axisLine, axisTick, splitLine, axisLabel, min, max }
]
}
function getCandleYAxis (args) {
const { dataType, digit } = args
const scale = true
const gridIndex = 1
const splitNumber = 2
const axisLine = SHOW_FALSE
const axisTick = SHOW_FALSE
const axisLabel = SHOW_FALSE
const splitLine = SHOW_FALSE
const formatter = (val) => {
return getFormated(val, dataType, digit)
}
return [
{ scale, axisTick, axisLabel: { formatter } },
{ scale, gridIndex, splitNumber, axisLine, axisTick, splitLine, axisLabel }
]
}
function getCandleDataZoom (args) {
const { start, end } = args
return [
{
type: 'inside',
xAxisIndex: [0, 1],
start,
end
},
{
show: true,
xAxisIndex: [0, 1],
type: 'slider',
top: '85%',
start,
end
}
]
}
function getCandleSeries (args) {
const {
values,
volumes,
upColor,
downColor,
showMA,
MA,
showVol,
labelMap,
digit,
itemStyle
} = args
const style = itemStyle || {
normal: {
color: upColor,
color0: downColor,
borderColor: null,
borderColor0: null
}
}
const lineStyle = { normal: { opacity: 0.5 } }
const series = [
{
name: labelMap[DEFAULT_K_NAME] == null
? DEFAULT_K_NAME
: labelMap[DEFAULT_K_NAME],
type: 'candlestick',
data: values,
itemStyle: style
}
]
if (showMA) {
MA.forEach(d => {
const name = `MA${d}`
series.push({
name: labelMap[name] == null ? name : labelMap[name],
data: calculateMA(d, values, digit),
type: 'line',
lineStyle,
smooth: true
})
})
}
if (showVol) {
series.push({
name: 'Volume',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
data: volumes
})
}
return series
}
function calculateMA (dayCount, data, digit) {
let result = []
data.forEach((d, i) => {
if (i < dayCount) {
result.push('-')
} else {
let sum = 0
for (let j = 0; j < dayCount; j++) sum += data[i - j][1]
result.push(+(sum / dayCount).toFixed(digit))
}
})
return result
}
export const candle = (columns, rows, settings, status) => {
const {
dimension = columns[0],
metrics = columns.slice(1, 6),
digit = 2,
itemStyle,
labelMap = {},
legendName = {},
MA = DEFAULT_MA,
showMA = false,
showVol = false,
showDataZoom = false,
downColor = DEFAULT_DOWN_COLOR,
upColor = DEFAULT_UP_COLOR,
start = DEFAULT_START,
end = DEFAULT_END,
dataType
} = settings
const { tooltipVisible, legendVisible } = status
const isLiteData = isArray(rows[0])
const dims = []
const values = []
const volumes = []
const candleMetrics = metrics.slice(0, 4)
const volumeMetrics = metrics[4]
if (isLiteData) {
rows.forEach(row => {
const itemResult = []
dims.push(row[columns.indexOf(dimension)])
candleMetrics.forEach(item => { itemResult.push(row[columns.indexOf(item)]) })
values.push(itemResult)
if (volumeMetrics) volumes.push(row[columns.indexOf(volumeMetrics)])
})
} else {
rows.forEach((row, index) => {
const itemResult = []
dims.push(row[dimension])
candleMetrics.forEach(item => { itemResult.push(row[item]) })
values.push(itemResult)
if (volumeMetrics) {
const status = row[metrics[0]] > row[metrics[1]] ? 1 : -1
volumes.push([index, row[volumeMetrics], status])
}
})
}
const legend = legendVisible && getCandleLegend({ showMA, MA, legendName, labelMap })
const tooltip = tooltipVisible && getCandleTooltip({ metrics, dataType, digit, labelMap })
const visualMap = showVol && getCandleVisualMap({ downColor, upColor, MA, showMA })
const dataZoom = showDataZoom && getCandleDataZoom({ start, end })
const grid = getCandleGrid({ showVol })
const xAxis = getCandleXAxis({ dims })
const yAxis = getCandleYAxis({ dataType, digit })
const series = getCandleSeries({
values,
volumes,
upColor,
downColor,
showMA,
MA,
showVol,
labelMap,
digit,
itemStyle
})
const axisPointer = { link: { xAxisIndex: 'all' } }
return { legend, tooltip, visualMap, grid, xAxis, yAxis, dataZoom, series, axisPointer }
}