| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- import defaultOption from "./chartOption"
- import { has, isArray, extend, extendDeep, getPercent, getTotal } from "@/core/utils/utils"
- const compatibleMultChartData = (data: any): any => {
- let arr: any = []
- if (has(data, "chartData")) {
- if (isArray(data.chartData)) {
- arr = extend(data.chartData)
- } else if (Object.keys(data.chartData)) {
- arr.push(extend(data.chartData))
- }
- }
- return arr
- }
- //获取兼容的chart对象
- const compatibleData = (data: any): any => {
- let obj = {}
- if (has(data, "chartData")) {
- if (isArray(data.chartData)) {
- obj = data.chartData[0]
- } else {
- obj = data.chartData
- }
- } else {
- obj = data
- }
- return obj
- }
- //获取兼容的SeriesData
- const compatibleSeries = (data: any): any => {
- let result = []
- if (has(data, "seriesData")) {
- result = data.seriesData
- } else if (has(data, "series")) {
- result = data.series
- } else {
- result = []
- }
- return result
- }
- /**
- * 获取某个配置项,并将其在原对象中删除 (保持eChart对象的干净)
- * @param key
- * @param options
- * @param defaultVal
- * @param objectType 0 值类型, 1 对象, 2 数组
- * @returns
- */
- const getOption = (options: any, key: string, defaultVal?: any) => {
- let type = 0
- if (typeof defaultVal == "object") {
- type = Array.isArray(defaultVal) ? 2 : 1
- }
- let val =
- type == 0 ? defaultVal : type == 1 ? Object.assign({}, defaultVal || {}) : Object.assign([], defaultVal || [])
- if (has(options, key)) {
- val = type == 0 ? options[key] : type == 1 ? extendDeep({}, val, options[key]) : extendDeep([], val, options[key])
- delete options[key]
- }
- return val
- }
- const lineBarSeriesOption = (chart: any, serieData: Array<any>, serieType: string, chartOptions: any) => {
- const _xAxisData = has(chart, "categories") ? chart.categories : []
- const legend: any = Object.assign({}, defaultOption.SIZE.legend, {
- type: getOption(chartOptions, "legendType", defaultOption.SIZE.legend.type),
- show: true,
- icon: getOption(chartOptions, "legendIcon", defaultOption.SIZE.legend.icon),
- data: [],
- })
- const tooltip = {
- show: getOption(chart, "showTooltip", true),
- trigger: "axis",
- axisPointer: {
- // 坐标轴指示器,坐标轴触发有效
- type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
- },
- }
- const totalArr: Array<any> = []
- if (has(serieData[0], "data")) {
- for (let i = 0; i < serieData[0].data.length; i++) {
- let temptotal = 0
- serieData.forEach((v: any) => {
- if (!v.data[i]) {
- v.data[i] = 0
- }
- temptotal += parseFloat(v.data[i])
- })
- totalArr.push(temptotal)
- }
- }
- const series = []
- let yAxisMax = 0
- let maxData = 0
- let showLabel = getOption(chartOptions, "showLabel", false)
- //const markPointStyles = getOption(chartOptions, "markPointStyles", [])
- //const markPointLabel = getOption(chartOptions, "markPointLabel", {})
- const markLineStyles = getOption(chartOptions, "markLineStyles", [
- {
- color: "#FF5147",
- },
- ])
- const markLineLabel = getOption(chartOptions, "markLineLabel", {
- color: "#FF5147",
- })
- const markAreaStyles = getOption(chartOptions, "markAreaStyles", {
- color: "rgba(255,81,71,0.2)",
- })
- const markAreaLabel = getOption(chartOptions, "markAreaLabel", {
- color: "#F2637B",
- offset: [31, 0],
- })
- const labelFormatter = getOption(chartOptions, "labelFormatter", undefined)
- const markPoint = getOption(chartOptions, "markPoint", {})
- const markLine = getOption(chartOptions, "markLine", {})
- const markArea = getOption(chartOptions, "markArea", {})
- const barGap = getOption(chartOptions, "barGap", defaultOption.SIZE.barGap)
- const symbol = getOption(chartOptions, "symbol", "circle")
- const smooth = getOption(chartOptions, "smooth", 0.5)
- const areaStyleColors = getOption(chartOptions, "areaStyle", [
- "rgba(56,164,90,.5)",
- "rgb(76,136,207,.3)",
- "rgb(255,185,126,.3)",
- ])
- const dataMarkLine = getOption(chart, "markLine", {})
- const dataMarkArea = getOption(chart, "markArea", {})
- serieData.forEach((v: any, i: number) => {
- legend.data.push({
- name: v.name,
- })
- if (typeof labelFormatter == "function") {
- showLabel = true
- }
- const type = has(v, "type") ? v.type : serieType
- let seriesOption: any = {
- type: type,
- name: v.name,
- data: v.data,
- stack: has(v, "stack") ? v.stack : null,
- itemStyle: getOption(v, "itemStyle", {}),
- markPoint,
- markLine,
- markArea,
- label: {
- show: showLabel,
- position: "",
- formatter: labelFormatter,
- fontSize: 10,
- },
- }
- seriesOption = Object.assign(
- seriesOption,
- type == "bar"
- ? {
- barWidth: defaultOption.SIZE.barWidth,
- barGap,
- //barMinWidth: defaultOption.SIZE.barMinWidth,
- barMaxWidth: defaultOption.SIZE.barMaxWidth,
- }
- : {
- symbol,
- symbolSize: defaultOption.SIZE.symbolSize,
- connectNulls: true,
- smooth,
- smoothMonotone: "x",
- areaStyle: {
- color: areaStyleColors[i],
- },
- }
- )
- if (v.data && v.data.length) {
- v.data.forEach((vv: any) => {
- if (vv > maxData) {
- maxData = vv
- }
- })
- yAxisMax = Math.floor(maxData * 1.2)
- }
- if (dataMarkLine) {
- seriesOption.markLine = dataMarkLine
- }
- if (has(chart, "warning")) {
- const markLine: any = {
- silent: true,
- label: markLineLabel,
- data: [
- {
- yAxis: chart.warning,
- },
- ],
- }
- if (markLineStyles && markLineStyles.length) {
- markLine.lineStyle = markLineStyles[i % markLineStyles.length]
- }
- if (chart.warning > maxData) {
- yAxisMax = Math.floor(chart.warning * 1.1)
- }
- seriesOption.markLine = markLine
- }
- if (dataMarkArea) {
- seriesOption.markArea = {
- data: dataMarkArea,
- label: markAreaLabel,
- itemStyle: markAreaStyles,
- }
- }
- const seriesItem = extendDeep(seriesOption, chartOptions.series || {})
- series.push(seriesItem)
- })
- if (getOption(chartOptions, "showTotal", false)) {
- series.push({
- name: "总计",
- type: serieType,
- stack: "total",
- markLine: {
- data: [
- { type: "max", name: "最大值" },
- { type: "min", name: "最小值" },
- ],
- label: { show: "true", position: "start" },
- lineStyle: {
- color: "rgba(255, 81, 71, 0.85)",
- },
- },
- itemStyle: {
- normal: {
- color: "rgba(128, 128, 128, 0)",
- },
- },
- data: totalArr,
- })
- }
- const axisLabel = getOption(chartOptions, "axisLabel", {})
- const axisLine = getOption(chartOptions, "axisLine", {})
- const splitLine = getOption(chartOptions, "splitLine", {})
- let xAxis: any = {
- show: true,
- type: "category",
- axisLabel,
- axisLine,
- splitLine,
- splitArea: getOption(chartOptions, "xSplitArea", {}),
- axisTick: {
- alignWithLabel: true,
- },
- data: _xAxisData,
- nameGap: defaultOption.SIZE.nameGap,
- boundaryGap: serieType != "line",
- }
- let yAxis: any = {
- show: true,
- name: getOption(chart, "yzTitle", ""),
- nameTextStyle: { align: "auto" },
- type: "value",
- max: yAxisMax ? yAxisMax : null,
- axisLabel: { ...axisLabel, formatter: getOption(chartOptions, "yAxisFormat", undefined) },
- axisLine,
- splitLine,
- splitArea: getOption(chartOptions, "ySplitArea", {}),
- axisTick: {
- alignWithLabel: true,
- },
- }
- //console.log("CHART_title", yAxis.name)
- const direction = getOption(chartOptions, "direction", false)
- if (direction) {
- //互换x,y轴
- if (direction == "y") {
- const tempX = xAxis
- const tempY = yAxis
- xAxis = Object.assign({}, tempY)
- yAxis = Object.assign({}, tempX)
- }
- }
- if (getOption(chartOptions, "inverseX", false)) {
- xAxis.inverse = true
- }
- if (getOption(chartOptions, "inverseY", false)) {
- yAxis.inverse = true
- }
- return { legend, tooltip, xAxis, yAxis, series }
- }
- const pieSeriesOption = (chart: any, serieData: Array<any>, serieType: string, chartOptions: any) => {
- const legend: any = {
- type: getOption(chartOptions, "legendType", defaultOption.SIZE.legend.type),
- show: true,
- icon: getOption(chartOptions, "legendIcon", defaultOption.SIZE.legend.icon),
- itemGap: defaultOption.SIZE.roseItemGap,
- data: [],
- }
- let showLabel = getOption(chartOptions, "showLabel", false)
- const showPercent = getOption(chartOptions, "showPercent", true)
- let labelFormatter = getOption(chartOptions, "labelFormatter", undefined)
- if (typeof labelFormatter == "function") {
- showLabel = true
- }
- if (!labelFormatter) {
- labelFormatter = "{b} ({c}) "
- }
- const title: any = {}
- const tooltip = {
- trigger: "item",
- formatter: labelFormatter,
- }
- const data: any = []
- const seriesOption: any = {
- type: "pie",
- center: getOption(chartOptions, "pieCenter", defaultOption.SIZE.pieCenter),
- radius: getOption(chartOptions, "pieRadius", defaultOption.SIZE.pieRadius),
- markPoint: getOption(chartOptions, "markPoint", {}),
- markLine: getOption(chartOptions, "markLine", {}),
- markArea: getOption(chartOptions, "markArea", {}),
- label: {
- show: showLabel,
- position: "outside",
- formatter: labelFormatter,
- },
- }
- const total = getTotal(serieData, has(serieData[0], "value") ? "value" : "data")
- const titleText = getOption(chartOptions, "titleText", getOption(chart, "yzTitle", "") ?? "")
- const titleUnit = getOption(chartOptions, "titleUnit", "")
- if (titleText) {
- if (titleUnit) {
- title.text = [`{title|${titleText}}`, `{total|${total}}`, `{unit|${titleUnit}}`].join("\n")
- } else {
- title.text = `{title|${titleText}}`
- }
- }
- const itemStyle = getOption(chartOptions, "pieItemStyle", undefined)
- serieData.forEach((v: any) => {
- const name = showPercent ? `${v.name}:${getPercent(total, v.value)}` : v.name
- legend.data.push({
- name,
- })
- const item: any = {
- name,
- value: v.value,
- }
- if (itemStyle) {
- item.itemStyle = itemStyle
- }
- data.push(item)
- })
- const series = [extendDeep(seriesOption, chartOptions.series || {}, { data })]
- return { legend, title, tooltip, series }
- }
- /**
- *
- * @param data 远程数据
- * @param options 为eChart的配置项
- 同时也可以单独配置
- serieType 图表类型
- showTotal 显示总数
- showLabel 显示数据标签
- labelFormatter 数据标签格式化
- markLineLabel 标记警告label (远程数据返回 "warning" 字段 生效)
- markLineStyles 标记警告线样式 (远程数据返回 "warning" 字段 生效)
- axisLabel 坐标轴label
- axisLine 坐标轴样式
- splitLine 分割线样式
- yAxisFormat y轴label格式化
- inverseX 反向坐标轴
- inverseY 反向坐标轴
- direction: 图表方向 'x' | 'y' (bar 类型生效)
- ...
- * @param serieType 图表类型
- * @returns eChart的配置项
- */
- const chart = (data: any, options: any, serieType?: string) => {
- if (data == null) {
- throw new Error("NO CHART DATA")
- }
- const _chart = compatibleData(data)
- const _series = compatibleSeries(_chart)
- const chartOptions = extend({}, options)
- serieType = getOption(chartOptions, "serieType", serieType)
- //const _xAxisData = has(_chart, "categories") ? _chart.categories : []
- //标题默认在图表下居中 ,使用远程数据 yzTitle 字段
- const title = {
- show: true,
- text:
- getOption(chartOptions, "titleText", "") || getOption(_chart, "title", "") || getOption(_chart, "yzTitle", ""),
- }
- const grid = Object.assign({}, defaultOption.SIZE.grid)
- let seriesOption = {}
- switch (serieType) {
- case "bar":
- case "line":
- seriesOption = lineBarSeriesOption(_chart, _series, serieType ?? "bar", chartOptions)
- break
- case "pie":
- seriesOption = pieSeriesOption(_chart, _series, serieType ?? "pie", chartOptions)
- break
- }
- const option = extendDeep({ title, grid }, seriesOption, chartOptions)
- return option
- //return Object.assign(true, {}, opt, options || {})
- }
- // const doubleTypes = (data: any, options: any, types = ["bar", "line"]) => {
- // if (data == null) {
- // throw new Error("no data")
- // }
- // const chartOptions = extendDeep({}, options)
- // const _charts = compatibleMultChartData(data)
- // const grid = Object.assign({}, defaultOption.SIZE.grid)
- // _charts.forEach((_chart: any, i: number) => {
- // const _series = compatibleSeries(_chart)
- // //标题默认在图表下居中 ,使用远程数据 title , yzTitle 字段
- // const title = {
- // show: true,
- // text: getOption(_chart, "title", "") || getOption(_chart, "yzTitle", ""),
- // }
- // })
- // }
- export default {
- bar(data: any, options: any) {
- return chart(data, options, "bar")
- },
- line(data: any, options: any) {
- return chart(data, options, "line")
- },
- pie(data: any, options: any) {
- return chart(data, options, "pie")
- },
- ring(data: any, options: any) {
- options = Object.assign({ pieRadius: defaultOption.SIZE.ringRadius }, options)
- return chart(data, options, "pie")
- },
- }
|