import { itemPoint } from '../../constants'
import { getFormated, getStackMap } from '../../utils'
import { set, get, cloneDeep } from 'utils-lite'
// default opacity of bar while dim-axis type is 'value'
const VALUE_AXIS_OPACITY = 0.5
function getBarDimAxis (args) {
const { innerRows, dimAxisName, dimension, axisVisible, dimAxisType, dims } = args
return dimension.map(item => ({
type: 'category',
name: dimAxisName,
nameLocation: 'middle',
nameGap: 22,
data: dimAxisType === 'value'
? getValueAxisData(dims)
: innerRows.map(row => row[item]),
axisLabel: {
formatter (v) {
return String(v)
}
},
show: axisVisible
}))
}
function getValueAxisData (dims) {
const max = Math.max.apply(null, dims)
const min = Math.min.apply(null, dims)
const result = []
for (let i = min; i <= max; i++) {
result.push(i)
}
return result
}
function getBarMeaAxis (args) {
const {
meaAxisName,
meaAxisType,
axisVisible,
digit,
scale,
min,
max
} = args
const meaAxisBase = {
type: 'value',
axisTick: {
show: false
},
show: axisVisible
}
let meaAxis = []
for (let i = 0; i < 2; i++) {
if (meaAxisType[i]) {
meaAxis[i] = Object.assign({}, meaAxisBase, {
axisLabel: {
formatter (val) {
return getFormated(val, meaAxisType[i], digit)
}
}
})
} else {
meaAxis[i] = Object.assign({}, meaAxisBase)
}
meaAxis[i].name = meaAxisName[i] || ''
meaAxis[i].scale = scale[i] || false
meaAxis[i].min = min[i] || null
meaAxis[i].max = max[i] || null
}
return meaAxis
}
function getBarTooltip (args) {
const { axisSite, isHistogram, meaAxisType, digit, labelMap } = args
let secondAxis = isHistogram
? axisSite.right || []
: axisSite.top || []
if (labelMap) {
secondAxis = secondAxis.map(item => {
return labelMap[item] === undefined ? item : labelMap[item]
})
}
return {
trigger: 'axis',
formatter (items) {
let tpl = []
tpl.push(`${items[0].name}
`)
items.forEach(item => {
const seriesName = item.seriesName
const type = ~secondAxis.indexOf(seriesName)
? meaAxisType[1]
: meaAxisType[0]
tpl.push(itemPoint(item.color))
tpl.push(`${seriesName}: `)
tpl.push(getFormated(item.value, type, digit))
tpl.push('
')
})
return tpl.join('')
}
}
}
function getValueData (seriesTemp, dims) {
const max = Math.max.apply(null, dims)
const min = Math.min.apply(null, dims)
const result = []
for (let i = min; i <= max; i++) {
const index = dims.indexOf(i)
if (~index) {
result.push(seriesTemp[index])
} else {
result.push(null)
}
}
return result
}
function getBarSeries (args) {
const {
innerRows,
metrics,
stack,
axisSite,
isHistogram,
labelMap,
itemStyle,
label,
showLine = [],
dimAxisType,
barGap,
opacity,
dims
} = args
let series = []
const seriesTemp = {}
const secondAxis = isHistogram
? axisSite.right || []
: axisSite.top || []
const secondDimAxisIndex = isHistogram ? 'yAxisIndex' : 'xAxisIndex'
const stackMap = stack && getStackMap(stack)
metrics.forEach(item => { seriesTemp[item] = [] })
innerRows.forEach(row => {
metrics.forEach(item => {
seriesTemp[item].push(row[item])
})
})
series = Object.keys(seriesTemp).map((item, index) => {
const data = dimAxisType === 'value'
? getValueData(seriesTemp[item], dims)
: seriesTemp[item]
const seriesItem = {
name: labelMap[item] != null ? labelMap[item] : item,
type: ~showLine.indexOf(item) ? 'line' : 'bar',
data,
[secondDimAxisIndex]: ~secondAxis.indexOf(item) ? '1' : '0'
}
if (stack && stackMap[item]) seriesItem.stack = stackMap[item]
if (label) seriesItem.label = label
if (itemStyle) seriesItem.itemStyle = itemStyle
let itemOpacity = opacity || get(seriesItem, 'itemStyle.normal.opacity')
if (dimAxisType === 'value') {
seriesItem.barGap = barGap
seriesItem.barCategoryGap = '1%'
if (itemOpacity == null) itemOpacity = VALUE_AXIS_OPACITY
}
if (itemOpacity != null) {
set(seriesItem, 'itemStyle.normal.opacity', itemOpacity)
}
return seriesItem
})
return series.length ? series : false
}
function getLegend (args) {
const { metrics, labelMap, legendName } = args
if (!legendName && !labelMap) return { data: metrics }
const data = labelMap
? metrics.map(item => (labelMap[item] == null ? item : labelMap[item]))
: metrics
return {
data,
formatter (name) {
return legendName[name] != null ? legendName[name] : name
}
}
}
function getDims (rows, dimension) {
return rows.map(row => row[dimension[0]])
}
export const bar = (columns, rows, settings, extra) => {
const innerRows = cloneDeep(rows)
const {
axisSite = {},
dimension = [columns[0]],
stack = {},
axisVisible = true,
digit = 2,
dataOrder = false,
scale = [false, false],
min = [null, null],
max = [null, null],
legendName = {},
labelMap = {},
label,
itemStyle,
showLine,
barGap = '-100%',
opacity
} = settings
const { tooltipVisible, legendVisible } = extra
let metrics = columns.slice()
if (axisSite.top && axisSite.bottom) {
metrics = axisSite.top.concat(axisSite.bottom)
} else if (axisSite.bottom && !axisSite.right) {
metrics = axisSite.bottom
} else if (settings.metrics) {
metrics = settings.metrics
} else {
metrics.splice(columns.indexOf(dimension[0]), 1)
}
const meaAxisType = settings.xAxisType || ['normal', 'normal']
const dimAxisType = settings.yAxisType || 'category'
const meaAxisName = settings.xAxisName || []
const dimAxisName = settings.yAxisName || ''
const isHistogram = false
if (dataOrder) {
const { label, order } = dataOrder
if (!label || !order) {
console.warn('Need to provide name and order parameters')
} else {
innerRows.sort((a, b) => {
if (order === 'desc') {
return a[label] - b[label]
} else {
return b[label] - a[label]
}
})
}
}
const dims = getDims(innerRows, dimension)
const legend = legendVisible && getLegend({ metrics, labelMap, legendName })
const yAxis = getBarDimAxis({
innerRows,
dimAxisName,
dimension,
axisVisible,
dimAxisType,
dims
})
const xAxis = getBarMeaAxis({
meaAxisName,
meaAxisType,
axisVisible,
digit,
scale,
min,
max
})
const series = getBarSeries({
innerRows,
metrics,
stack,
axisSite,
isHistogram,
labelMap,
itemStyle,
label,
showLine,
dimAxisType,
dimension,
barGap,
opacity,
dims
})
const tooltipParams = { axisSite, isHistogram, meaAxisType, digit, labelMap }
const tooltip = tooltipVisible && getBarTooltip(tooltipParams)
const options = { legend, yAxis, series, xAxis, tooltip }
return options
}
export const histogram = (columns, rows, settings, status) => {
const innerRows = cloneDeep(rows)
const {
axisSite = {},
dimension = [columns[0]],
stack = {},
axisVisible = true,
digit = 2,
dataOrder = false,
scale = [false, false],
min = [null, null],
max = [null, null],
labelMap = {},
legendName = {},
label,
itemStyle,
showLine,
barGap = '-100%',
opacity
} = settings
if (dataOrder) {
const { label, order } = dataOrder
if (!label || !order) {
console.warn('Need to provide name and order parameters')
} else {
innerRows.sort((a, b) => {
if (order === 'desc') {
return a[label] - b[label]
} else {
return b[label] - a[label]
}
})
}
}
const { tooltipVisible, legendVisible } = status
let metrics = columns.slice()
if (axisSite.left && axisSite.right) {
metrics = axisSite.left.concat(axisSite.right)
} else if (axisSite.left && !axisSite.right) {
metrics = axisSite.left
} else if (settings.metrics) {
metrics = settings.metrics
} else {
metrics.splice(columns.indexOf(dimension[0]), 1)
}
const meaAxisType = settings.yAxisType || ['normal', 'normal']
const dimAxisType = settings.xAxisType || 'category'
const meaAxisName = settings.yAxisName || []
const dimAxisName = settings.xAxisName || ''
const isHistogram = true
const dims = getDims(innerRows, dimension)
const legend = legendVisible && getLegend({ metrics, labelMap, legendName })
const xAxis = getBarDimAxis({
innerRows,
dimAxisName,
dimension,
axisVisible,
dimAxisType,
dims
})
const yAxis = getBarMeaAxis({
meaAxisName,
meaAxisType,
axisVisible,
digit,
scale,
min,
max
})
const series = getBarSeries({
innerRows,
metrics,
stack,
axisSite,
isHistogram,
labelMap,
itemStyle,
label,
showLine,
dimAxisType,
dimension,
barGap,
opacity,
dims
})
const tooltipParams = { axisSite, isHistogram, meaAxisType, digit, labelMap }
const tooltip = tooltipVisible && getBarTooltip(tooltipParams)
const options = { legend, yAxis, series, xAxis, tooltip }
return options
}