# echart案例
# 饼图
# 旋转轮播饼图
/** 旋转轮播饼图 */
var dsValue = data.a('xg.dataValue') || {} // 数据集结果
var seriesData = dsValue['series'] || [];
var seriesDataLen = seriesData.length
var labelName = seriesData[0].name
var labelValue = seriesData[0].value
var labelPercent = ''
// 全局样式
var defaultGlobalStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.GLOBAL_STYLES), { 'lineStyle': BI.EchartConfig.LINE_STYLES })
var globalStyle = Object.assign(defaultGlobalStyle, data.a('xg.echarts.global'))
const { backgroundColor, grid } = globalStyle;
// 图例
var defaultLegendStyle = Object.assign(
{},
ht.Default.clone(BI.EchartConfig.LEGEND_STYLES),
{ proportionStyle: ht.Default.clone(BI.EchartConfig.PIE_PROPORTION_STYLES) },
{ realValue: ht.Default.clone(BI.EchartConfig.PIE_REALVALUE_STYLES) },
{ suffixStyle: ht.Default.clone(BI.EchartConfig.SUFFIX_STYLES) },
{ categoryStyle: ht.Default.clone(BI.EchartConfig.CATEGORY_STYLES) },
)
var legendStyle = Object.assign(defaultLegendStyle, data.a('xg.echarts.legend'))
const { icon, itemHeight, itemWidth, layout, textStyle, lengedGap, selectedMode } = legendStyle
//提示框
var defaultTipsStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.TIPS_STYLE))
var tipsStyle = Object.assign(defaultTipsStyle, data.a('xg.echarts.tips'))
var tooltipIndex = 0;
// 系列 BI.EchartConfig.SERIES_STYLES
let defaultSeriesStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.SERIES_STYLES))
let seriesStyle = Object.assign(defaultSeriesStyle, data.a('xg.echarts.series'))
console.log('系列', seriesStyle)
// 保留小数函数
function retainDecimals(value, decimalDigit) {
let newValue = ''
const arr = String(value).split(".")
const decimalLen = arr[1]?.length ?? 0
if (decimalDigit === 0) {
newValue = arr[0]
} else if (decimalDigit > decimalLen) {
const len = decimalDigit - decimalLen
const str = "".padStart(len, '0')
const decimalContent = arr[1] ?? ""
newValue = arr[0] + "." + decimalContent + str
}
return newValue
}
// 转rgba
function changeColor(hex) {
let color = ''
let r, g, b, a = 1;
let changeVal = 30
// 确保hex以#开头
if (hex.charAt(0) === '#') {
hex = hex.slice(1);
// 解析红色、绿色和蓝色通道的值
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
// color =`rgba(${r},${g},${b},1)`
} else if (!hex.includes('rgba') && hex.includes('rgb')) {
const rgbRegex = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/;
const match = hex.match(rgbRegex);
r = parseInt(match[1], 10)
g = parseInt(match[2], 10)
b = parseInt(match[3], 10)
// color= `rgba(${r},${g},${b},1)`
} else if (hex.includes('rgba')) {
const rgbRegex = /rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)/;
const match = hex.match(rgbRegex);
r = parseInt(match[1], 10)
g = parseInt(match[2], 10)
b = parseInt(match[3], 10)
a = parseInt(match[4], 10) * 1
// color= `rgba(${r},${g},${b},${a})`
// return color
}
if (typeof r === 'number') {
if (r - changeVal >= 0) {
r -= changeVal
}
if (g - changeVal >= 0) {
g -= changeVal
}
if (b - changeVal <= 0) {
b -= changeVal
}
color = `rgba(${r},${g},${b},${a * 0.2})`
return color
}
return hex
}
let sum = 0
seriesData.forEach(el => {
sum += el.value
})
labelPercent = parseInt((seriesData[0].value / sum) * 100)
let data1 = [];
let data2 = [];
let data3 = [];
let addDeg = 0;
let deg = 0;
let gapValue = Math.ceil((sum / 100) * 1)
let styleMap = new Map()
seriesData.map((v, k) => {
styleMap.set(v.name, k)
addDeg = addDeg - (v.value / sum * 360);
deg = addDeg + (v.value / sum * 180);
data1.push({
...v,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: seriesStyle[k]?.itemStyle?.startColor ?? seriesStyle[0]?.itemStyle?.startColor
},
{
offset: 1, color: seriesStyle[k]?.itemStyle?.endColor ?? seriesStyle[0]?.itemStyle?.startColor
}],
}
}
})
data3.push(v)
data2.push({
...v,
// label:{
// rotate:deg,
// animation:false,
// },
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: seriesStyle[k]?.itemStyle?.startColor ? changeColor(seriesStyle[k].itemStyle.startColor) : seriesStyle[0]?.itemStyle?.startColor,
// color: seriesStyle[k]?.itemStyle?.startColor ?? seriesStyle[0]?.itemStyle?.startColor
},
{
offset: 1,
color: seriesStyle[k]?.itemStyle?.startColor ? changeColor(seriesStyle[k].itemStyle.startColor) : seriesStyle[0]?.itemStyle?.startColor,
}],
}
}
})
// pieData.push({
// value:gapValue,
// name:"",
// itemStyle:{
// color:backgroundColor
// }
// })
})
// let pieData = [];
// let addDeg = 0;
// let deg = 0;
// for (let i = 0; i < seriesData.length; i++) {
// // 计算 label 的旋转角度
// addDeg = addDeg - (seriesData[i].value/sum*360);
// deg = addDeg + (seriesData[i].value/sum*180);
// pieData.push({
// value: seriesData[i].value,
// name: seriesData[i].name,
// label:{
// rotate:deg
// }
// });
// }
let richObject = {}
function settingColorForLegend(richObject = {}) {
// 标签
richObject.styleLabel = {
...legendStyle.categoryStyle.textStyle
}
// 值
// 值是否跟随系列色
// 百分比
if (legendStyle.proportionStyle.followColor) {
seriesData.forEach((el, index) => {
richObject['stylePrecent' + index] = {
...legendStyle.proportionStyle.textStyle,
color: seriesStyle[index].itemStyle.startColor
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['stylePrecent' + index] = {
...legendStyle.proportionStyle.textStyle
}
})
}
// 真实值 styleRealVal
if (legendStyle.realValue.followColor) {
seriesData.forEach((el, index) => {
richObject['styleRealVal' + index] = {
...legendStyle.realValue.textStyle,
color: seriesStyle[index].itemStyle.startColor
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['styleRealVal' + index] = {
...legendStyle.realValue.textStyle
}
})
}
// 后缀 styleSuffix
if (legendStyle.realValue.followColor) {
seriesData.forEach((el, index) => {
richObject['styleSuffix' + index] = {
...legendStyle.realValue.textStyle,
color: seriesStyle[index].itemStyle.startColor,
fontSize: legendStyle.suffixStyle.fontSize
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['styleSuffix' + index] = {
...legendStyle.realValue.textStyle,
fontSize: legendStyle.suffixStyle.fontSize
}
})
}
// console.warn(richObject)
return richObject
}
richObject = settingColorForLegend(richObject)
function porpertyShow(parent, type) {
if (parent === 'legend') {
if (type === 'realValue') {
return legendStyle.realValue.show ?? false
} else if (type === 'percentVal') {
return legendStyle.proportionStyle.show ?? false
} else if (type === 'suffix') {
return legendStyle.suffixStyle.show ?? false
}
}
return true
}
const percentageArr = []
seriesData.forEach((el, index) => {
percentageArr.push({
name: el.name,
value: (el.value / sum * 100).toFixed(0)
})
})
function getPercentFun(name) {
let val = ''
percentageArr.some(el => {
if (el.name === name) {
val = el.value + "%"
return true
}
})
return val
}
var option = {
color: ['rgb(32, 173, 255)', 'rgb(30, 231, 231)', 'orange', 'red', 'purple'],
backgroundColor: backgroundColor,
grid: Object.assign({
containLabel: true
}, grid),
tooltip: {
show: true
},
tooltip1: {
show: false ?? tipsStyle.hoverTrigger,
backgroundColor: tipsStyle.tooltip.backgroundColor,
// padding: [defaultTipsStyle.tooltip.position.top,0,0,0],
trigger: 'axis',
position: function (pos) {
var offsetX = tipsStyle.tooltip.offset[0]; // 水平偏移量
var offsetY = tipsStyle.tooltip.offset[1]; // 垂直偏移量
return [pos[0] + offsetX, pos[1] - offsetY];
},
axisPointer: {
type: 'line',
lineStyle: {
type: 'solid', // 设置线条类型为实线
color: tipsStyle.indicator.color, // 设置指示器颜色
width: tipsStyle.indicator.width // 设置指示器线条宽度
},
},
borderWidth: 0,
// borderColor:"red",
formatter: function (params) {
var tipHtml = ''; // 自定义提示框内容
// 标题部分
const titleMes = tipsStyle.categoryLabel
tipHtml += `<div style="
font-weight:${titleMes.textStyle.fontWeight};
font-Family:${titleMes.textStyle.fontFamily};
font-size:${titleMes.textStyle.fontSize}px;
color:${titleMes.textStyle.color};
line-height:${titleMes.textStyle.lineHeight}px;
font-style:${titleMes.textStyle.fontStyle};
text-align:${titleMes.textAlign};
position:relative;
left:${titleMes.offset[0]}px;
top:${titleMes.offset[1]}px
"
>
${params[0].name}
</div>`;
// 数据项部分
const contentLabel = tipsStyle.categoryData.labelStyle
const contentValue = tipsStyle.categoryData.valueStyle
const suffix = tipsStyle.dataSuffix
const suffixStyle = tipsStyle.dataSuffix.textStyle
const iconSize = tipsStyle.categoryData.iconSize
params.forEach(function (item, index) {
// TODO 提示框图标颜色
const temColor = seriesStyle[index].itemStyle.startColor;
var market = `<span style="display:inline-block;margin-right:4px;width:${iconSize}px;height:${iconSize}px;background-color:${temColor};"></span>`
const newValue = retainDecimals(item.value, tipsStyle.categoryData.decimal ?? 0)
tipHtml += `
${market}
<span
style="
font-weight:${contentLabel.fontWeight};
font-Family:${contentLabel.fontFamily};
font-size:${contentLabel.fontSize}px;
color:${contentLabel.color};
line-height:${contentLabel.lineHeight}px;
font-style:${contentLabel.fontStyle};
"
>
${item.seriesName}:
</span>
<span
style="
font-weight:${contentValue.fontWeight};
font-Family:${contentValue.fontFamily};
font-size:${contentValue.fontSize}px;
color:${contentValue.color};
line-height:${contentValue.lineHeight}px;
font-style:${contentValue.fontStyle};
">
${newValue}
</span>`;
if (suffix.name) {
tipHtml += `<span
font-weight:${suffixStyle.fontWeight};
font-Family:${suffixStyle.fontFamily};
font-size:${suffixStyle.fontSize}px;
color:${suffixStyle.color};
line-height:${suffixStyle.lineHeight}px;
font-style:${suffixStyle.fontStyle};
position:relative;
left:${suffix.offset[0]}px;
top:${suffix.offset[1]}px
>${suffix.name}</span><br/>`
} else {
tipHtml += `<br/>`
}
});
tooltipHtml = `<div
style= "
box-sizing: border-box !important;
width:${tipsStyle.tooltip.width}px;
height:${tipsStyle.tooltip.height}px;
padding:${tipsStyle.tooltip.top}px ${tipsStyle.tooltip.right}px ${tipsStyle.tooltip.bottom}px ${tipsStyle.tooltip.left}px
">
${tipHtml}
</div>`
return tooltipHtml;
}
},
legend: {
// icon: icon, // rect
// itemWidth: itemWidth, // 设置宽度
// itemHeight: itemHeight, // 设置高度
// top: 'center',
// // left: layout.position.left,
// left: 'right',
// orient: 'vertical',
// textStyle: Object.assign({
// padding: [0, 0, 0, lengedGap]
// }, textStyle,{lineHeight:12}),
// // itemGap: layout.itemGap.columnGap,
// selectedMode: selectedMode,
// show: true,
orient: 'vertical',
icon: icon, // rect
itemWidth: itemWidth, // 设置宽度
itemHeight: itemHeight, // 设置高度
top: 'center',
// bottom:"5%",
right: 'right',
textStyle: Object.assign({
padding: [0, 0, 0, lengedGap]
}, textStyle, { lineHeight: (textStyle?.lineHeight ?? 12) / 2 }, {
rich: richObject
}),
// itemGap: layout.itemGap.columnGap,
selectedMode: false,
align: 'left',
orient: 'horizontal',
show: true,
formatter: function (params) {
const index = styleMap.get(params)
let suffix = legendStyle.suffixStyle.name
// 真实值 占比值 后缀值 是否存在
let trutyVisible = porpertyShow('legend', 'realValue')
let percentVisible = porpertyShow('legend', 'percentVal')
let suffixVisible = porpertyShow('legend', 'suffix')
let legendHTML = ''
if (!trutyVisible && !percentVisible) {
// return `{style1|${params.name}}`
legendHTML = `{styleLabel|${params}}`
} else if (!trutyVisible && percentVisible) {
legendHTML = `{styleLabel|${params}} {stylePrecent${index}|${percentageArr[index].value}%}`
} else if (trutyVisible && !percentVisible) {
if (suffixVisible) {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}{styleSuffix|${suffix}}`
} else {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}`
}
} else if (trutyVisible && percentVisible) {
if (suffixVisible) {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}{styleSuffix|${suffix}} {stylePrecent${index}|${percentageArr[index].value}%}`
} else {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}} {stylePrecent${index}|${percentageArr[index].value}%}`
}
}
return legendHTML
}
},
series: []
};
// 动画渲染
if (!cache.htmlView) {
cache.htmlView = document.createElement('div');
cache.htmlView.style.position = 'absolute';
cache.htmlView.symbolName = data.getDisplayName() || '旋转轮播饼图'
requestAnimationFrame(() => {
cache.htmlChart = echarts.init(cache.htmlView);
cache.htmlChart.setOption(option);
// cache.htmlChart && addLoopAnimation(cache.htmlChart)
loopPie(pieIndex)
pieIndex++
cache.pieIndex = pieIndex
// 交互配置
InteractionUtil.AddInteractionEvent(gv.dm(), cache.htmlChart, data)
});
cache.htmlView.layoutHTML = function () {
gv.layoutHTML(data, cache.htmlView, true);
cache.htmlChart && cache.htmlChart.resize();
};
cache.htmlView.onHTMLAdded = function () {
}
cache.htmlView.onHTMLRemove = function () {
clearInterval(cache.timer)
cache.lastColor = null
cache.lastColor1 = null
cahce.pieIndex = ''
// cache.legend = null
}
}
option.series = [];
option.legend.data = [];
// if(!cache.legend){
// cache.legend = []
seriesData.forEach((el, index) => {
var displayName = BI.EchartUtil.getSeriesDisplayName(data, el, index)
const seriesStyle = BI.EchartUtil.getSeriesItemStyle(data, index)
option.legend.data.push({
name: displayName,
itemStyle: {
color: seriesStyle.lineStyle.color
}
});
// cache.legend.push(displayName || `图例${index}`)
})
// option.legend.data = cache.legend
// }
// 系列一 ,偏转 90度 + 自身弧度制的一半
// 先假设空隙不存在
const totalAll = []
seriesData.reduce((total, current, index) => {
let val = parseInt((total + current.value / 2) / sum * 360)
totalAll.push(val)
total += current.value
return total
}, 0)
// console.warn(totalAll)
option.series = [{
name: 'Access From',
type: 'pie',
radius: ['55%', '60%'],
data: data1,
label: {
show: false,
position: 'center',
// formatter:function(params){
// console.warn(params.name)
// let html = ''
// html+='1111' + params.name
// return html
// },
// rich:{
// }
// formatter: [
// '{a|这段文本采用样式a}',
// '{b|这段文本采用样式b}这段用默认样式{x|这段用样式x}'
// ].join('\n'),
// formatter: function (params) {
// return `{style1|${params.name}}\n{style2|${params.value}}\n{style3|${params.percent}%}`
// },
formatter: `{style1|${labelName}}\n{style2|${labelValue}}\n{style3|${labelPercent}%}`,
rich: {
textAlign: "center",
fontSize: 8,
style1: {
color: '#E6F7FF',
lineHeight: 18
},
style2: {
color: '#E6F7FF',
lineHeight: 18
},
style3: {
color: '#E6F7FF',
lineHeight: 18
},
}
},
emphasis: {
scale: false,
label: {
show: true,
}
},
},
{
name: 'Access From',
type: 'pie',
tooltip: {
show: false
},
radius: ['60%', '90%'],
data: data2,
label: {
show: false,
position: "inside",
// rotate:'tangential',
itemStyle: {
color: "#FFF"
},
// rotate:true
},
emphasis: {
show: false,
scale: false
}
},
{
name: 'Access From',
type: 'pie',
radius: ['55%', '60%'],
data: data3,
label: {
show: false,
position: 'center',
// formatter:function(params){
// console.warn(params.name)
// let html = ''
// html+='1111' + params.name
// return html
// },
// rich:{
// }
// formatter: [
// '{a|这段文本采用样式a}',
// '{b|这段文本采用样式b}这段用默认样式{x|这段用样式x}'
// ].join('\n'),
// formatter: function (params) {
// return `{style1|${params.name}}\n{style2|${params.value}}\n{style3|${params.percent}%}`
// },
formatter: `{style1|${labelName}}\n{style2|${labelValue}}\n{style3|${labelPercent}%}`,
rich: {
textAlign: "center",
fontSize: 8,
style1: {
color: '#E6F7FF',
lineHeight: 18
},
style2: {
color: '#E6F7FF',
lineHeight: 18
},
style3: {
color: '#E6F7FF',
lineHeight: 18
},
}
},
emphasis: {
scale: false,
label: {
show: true,
}
},
itemStyle:{
color:backgroundColor
},
},
]
// cache.htmlChart && cache.htmlChart.setOption(option, true);
let pieIndex = 0
if(cache.pieIndex>=0 && typeof cache.pieIndex === 'number'){
pieIndex = cache.pieIndex
}
let changeData = ht.Default.clone(data2)
function loopPie(i) {
// 文字跟随转动
// changeData.forEach((el,index)=>{
// // el.label.rotate = data2[index].label.rotate + totalAll[i]
// el.label.rotate = 'tangential'
// })
// option.series[1].data = changeData
// 圆环变动
option.series[0].startAngle = 90 + totalAll[i]
option.series[1].startAngle = 90 + totalAll[i]
option.series[2].startAngle = 90 + totalAll[i]
// cache.htmlChart.dispatchAction({
// type: 'downplay',
// seriesIndex: 0,
// dataIndex: i - 2
// });
// options.series[1].label = {
// postion: 'center',
// formatter:function(){
// return data2[i].name
// }
// }
// window.requestAnimationFrame(() => {
// setTimeout(()=>{
if (i === 0) {
cache.htmlChart.dispatchAction({
type: 'downplay',
seriesIndex: 2,
dataIndex: seriesDataLen - 1
});
if (cache.lastColor) {
option.series[0].data[seriesDataLen - 1].itemStyle.color = cache.lastColor
option.series[1].data[seriesDataLen - 1].itemStyle.color = cache.lastColor1
}
} else {
cache.htmlChart.dispatchAction({
type: 'downplay',
seriesIndex: 2,
dataIndex: i - 1
});
if (cache.lastColor) {
option.series[0].data[i - 1].itemStyle.color = cache.lastColor
option.series[1].data[i - 1].itemStyle.color = cache.lastColor1
}
}
// cache.lastColor = data1.itemStyle.color
cache.lastColor = ht.Default.clone(option.series[0].data[i].itemStyle.color)
cache.lastColor1 = ht.Default.clone(option.series[1].data[i].itemStyle.color)
const lightColor = {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(203,97,8,1)'
},
{
offset: 1, color: 'rgba(203,97,8,1)'
}],
}
const lightColor1 = {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(183,77,8,0.3)'
},
{
offset: 1, color: 'rgba(183,77,8,0.3)'
}],
}
option.series[0].data[i].itemStyle.color = lightColor
option.series[1].data[i].itemStyle.color = lightColor1
cache.htmlChart.dispatchAction({
type: 'highlight',
seriesIndex: 2,
dataIndex: i
});
labelName = seriesData[i].name
labelValue = seriesData[i].value
labelPercent = parseInt((labelValue / sum) * 100)
// 避免悬浮时环形label重叠
option.series[2].label.formatter = `{style1|${labelName}}\n{style2|${labelValue}}\n{style3|${labelPercent}%}`
cache.htmlChart && cache.htmlChart.setOption(option, true);
// })
// })
// cache.htmlChart && cache.htmlChart.setOption(option, true);
}
// if(typeof cache.pieIndex !== 'number'){
// loopPie(pieIndex)
// pieIndex++
// }
cache.pieIndex = pieIndex
if (!cache.timer) {
clearInterval(cache.timer)
cache.timer = setInterval(() => {
loopPie(pieIndex)
if (pieIndex + 1 >= seriesDataLen) {
pieIndex = 0
cache.pieIndex = pieIndex
} else {
pieIndex++
cache.pieIndex = pieIndex
}
}, 3000)
}
return cache.htmlView;
# 基本环图
/** 基本环图 */
var dsValue = data.a('xg.dataValue') || {} // 数据集结果
// 全局样式
var defaultGlobalStyle = Object.assign(
{},
ht.Default.clone(BI.EchartConfig.GLOBAL_STYLES),
{ valueLabel: ht.Default.clone(BI.EchartConfig.PIE_VALUELABEL_STYLES) },
{ proportionStyle: ht.Default.clone(BI.EchartConfig.PIE_PROPORTION_STYLES) },
{ realValue: ht.Default.clone(BI.EchartConfig.PIE_REALVALUE_STYLES) },
{ suffixStyle: ht.Default.clone(BI.EchartConfig.SUFFIX_STYLES) },
{ categoryStyle: ht.Default.clone(BI.EchartConfig.CATEGORY_STYLES) },
)
var globalStyle = Object.assign(defaultGlobalStyle, data.a('xg.echarts.global'))
const { backgroundColor, grid } = globalStyle;
// 图例
var defaultLegendStyle = Object.assign(
{},
ht.Default.clone(BI.EchartConfig.LEGEND_STYLES),
{ proportionStyle: ht.Default.clone(BI.EchartConfig.PIE_PROPORTION_STYLES) },
{ realValue: ht.Default.clone(BI.EchartConfig.PIE_REALVALUE_STYLES) },
{ suffixStyle: ht.Default.clone(BI.EchartConfig.SUFFIX_STYLES) },
{ categoryStyle: ht.Default.clone(BI.EchartConfig.CATEGORY_STYLES) },
)
var legendStyle = Object.assign(defaultLegendStyle, data.a('xg.echarts.legend'))
// console.log('图例:', defaultLegendStyle)
const { icon, itemHeight, itemWidth, layout, textStyle, lengedGap, selectedMode } = legendStyle
// console.warn(legendStyle)
// 系列 BI.EchartConfig.SERIES_STYLES
let defaultSeriesStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.SERIES_STYLES))
let seriesStyle = Object.assign(defaultSeriesStyle, data.a('xg.echarts.series'))
// console.log('系列', seriesStyle)
// 环图
let defaultRingGraph = Object.assign({},ht.Default.clone(BI.EchartConfig.PIE_RING_STYLES),data.a('xg.echarts.ringGraph'))
// console.warn(BI.EchartConfig.PIE_RING_STYLES)
// console.warn(data.a('xg.echarts.ringGraph'))
// console.warn(defaultRingGraph)
// console.warn(data.a('xg.echarts.ringGraph'))
var option = {
backgroundColor: backgroundColor,
grid: Object.assign({
containLabel: true
}, grid),
tooltip: {
show: true,
// trigger: 'axis',
// axisPointer: {
// type: 'line',
// lineStyle: {
// color: '#ffa147',
// width: 1,
// type: 'dashed'
// }
// }
},
legend: {
icon: icon, // rect
itemWidth: itemWidth, // 设置宽度
itemHeight: itemHeight, // 设置高度
top: 'top',
left: 'right',
textStyle: Object.assign({
padding: [0, 0, 0, lengedGap]
}, textStyle),
itemGap: layout.itemGap.columnGap,
selectedMode: selectedMode,
show: true
},
series: []
};
var seriesData = dsValue['series'] || [];
const pieData = []
const pieData1 = []
let sum = 0
seriesData.forEach(el => {
sum += el.value
})
// 设置间隙
let gapValue = Math.ceil((sum / 100) * defaultRingGraph.graphical.borderWidth*0.5)
let styleMap = new Map()
seriesData.map((v, k) => {
styleMap.set(v.name, k)
pieData.push({
...v,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: seriesStyle[k]?.itemStyle?.startColor ?? seriesStyle[0]?.itemStyle?.startColor
},
{
offset: 1, color: seriesStyle[k]?.itemStyle?.endColor ?? seriesStyle[0]?.itemStyle?.startColor
}],
}
}
})
pieData.push({
value: gapValue,
name: "",
itemStyle: {
color: backgroundColor
}
})
})
seriesData.map((v, k) => {
pieData1.push({
...v,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: seriesStyle[k]?.itemStyle?.startColor ?? seriesStyle[0]?.itemStyle?.startColor
},
{
offset: 1, color: seriesStyle[k]?.itemStyle?.endColor ?? seriesStyle[0]?.itemStyle?.startColor
}],
}
}
})
pieData1.push({
value: 1,
name: "",
itemStyle: {
color: backgroundColor
}
})
})
var option0;
var option1;
let richObject = {}
function settingColorForLegend(richObject = {}) {
// 标签
richObject.styleLabel = {
...legendStyle.categoryStyle.textStyle
}
// 值
// 值是否跟随系列色
// 百分比
if (legendStyle.proportionStyle.followColor) {
seriesData.forEach((el, index) => {
richObject['stylePrecent' + index] = {
...legendStyle.proportionStyle.textStyle,
color: seriesStyle[index].itemStyle.startColor
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['stylePrecent' + index] = {
...legendStyle.proportionStyle.textStyle
}
})
}
// 真实值 styleRealVal
if (legendStyle.realValue.followColor) {
seriesData.forEach((el, index) => {
richObject['styleRealVal' + index] = {
...legendStyle.realValue.textStyle,
color: seriesStyle[index].itemStyle.startColor
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['styleRealVal' + index] = {
...legendStyle.realValue.textStyle
}
})
}
// 后缀 styleSuffix
if (legendStyle.realValue.followColor) {
seriesData.forEach((el, index) => {
richObject['styleSuffix' + index] = {
...legendStyle.realValue.textStyle,
color: seriesStyle[index].itemStyle.startColor,
fontSize:legendStyle.suffixStyle.fontSize
}
})
} else {
// 如果不是,获取参数是从配置表中拿统一的
seriesData.forEach((el, index) => {
richObject['styleSuffix' + index] = {
...legendStyle.realValue.textStyle,
fontSize:legendStyle.suffixStyle.fontSize
}
})
}
// console.warn(richObject)
return richObject
}
richObject = settingColorForLegend(richObject)
// function getSuffix(parent,name){
// if(parent === 'global'){
// ser
// }
// }
// porpertyShow('global','precentVal')
function porpertyShow(parent, type) {
if (parent === 'global') {
if (type === 'realValue') {
return globalStyle.realValue.show ?? false
} else if (type === 'percentVal') {
return globalStyle.proportionStyle.show ?? false
} else if (type === 'suffix') {
return globalStyle.suffixStyle.show ?? false
}
} else if (parent === 'legend') {
if (type === 'realValue') {
return legendStyle.realValue.show ?? false
} else if (type === 'percentVal') {
return legendStyle.proportionStyle.show ?? false
} else if (type === 'suffix') {
return legendStyle.suffixStyle.show ?? false
}
}
return true
}
const percentageArr = []
seriesData.forEach((el, index) => {
percentageArr.push({
name: el.name,
value: (el.value / sum * 100).toFixed(0)
})
})
function getPercentFun(name) {
let val = ''
percentageArr.some(el => {
if (el.name === name) {
val = el.value + "%"
return true
}
})
return val
}
function decorationFun(){
let decopacity = defaultRingGraph.decoration.opacity / 100
let direction = defaultRingGraph.decoration.direction === "CW"? 'rotate-forever':'rotate-forever1'
let time = defaultRingGraph.decoration.speed=== 0 ?0: defaultRingGraph.decoration.speed
if(cache.kchild1){
cache.kchild1.style.cssText = `position:absolute;zIndex:10;top:0;left:0;width:100%;height:100%;opacity:${decopacity};animation:${direction} ${time}s linear infinite;transform-origin:36%`
}
}
option0 = {
tooltip: {
trigger: 'item'
},
grid: Object.assign({
containLabel: true
}, grid),
legend: {
orient: 'vertical',
icon: icon, // rect
itemWidth: itemWidth, // 设置宽度
itemHeight: itemHeight, // 设置高度
top: 'center',
// bottom:"5%",
right: 'right',
textStyle: Object.assign({
padding: [0, 0, 0, lengedGap]
}, textStyle, { lineHeight: (textStyle?.lineHeight ?? 12) / 2 }, {
rich: richObject
// rich:{
// styleLabel:{
// color:'#FFF',
// fontSize:10,
// },
// styleValue1:{
// color:'blue',
// fontSize:10,
// }
// }
}),
// itemGap: layout.itemGap.columnGap,
selectedMode: selectedMode,
align: 'left',
orient: 'horizontal',
show: true,
itemGap: 8,
formatter: function (params) {
const index = styleMap.get(params)
let suffix = legendStyle.suffixStyle.name
// 真实值 占比值 后缀值 是否存在
let trutyVisible = porpertyShow('legend', 'realValue')
let percentVisible = porpertyShow('legend', 'percentVal')
let suffixVisible = porpertyShow('legend', 'suffix')
let legendHTML = ''
if (!trutyVisible && !percentVisible) {
// return `{style1|${params.name}}`
legendHTML = `{styleLabel|${params}}`
} else if (!trutyVisible && percentVisible) {
legendHTML = `{styleLabel|${params}} {stylePrecent${index}|${percentageArr[index].value}%}`
} else if (trutyVisible && !percentVisible) {
if (suffixVisible) {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}{styleSuffix|${suffix}}`
} else {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}`
}
} else if (trutyVisible && percentVisible) {
if (suffixVisible) {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}}{styleSuffix|${suffix}} {stylePrecent${index}|${percentageArr[index].value}%}`
} else {
legendHTML = `{styleLabel|${params}}{styleRealVal${index}|${seriesData[index].value}} {stylePrecent${index}|${percentageArr[index].value}%}`
}
}
// const legendHTML = `{styleLabel|${params}}{styleRealVal|${seriesData[index].value}}{styleSuffix|${suffix}} {stylePrecent${index}|${percentageArr[index].value}%}`
// return `<div>333</div>`
return legendHTML
}
},
tooltip: {
show: true ?? tipsStyle.hoverTrigger,
// backgroundColor: tipsStyle.tooltip.backgroundColor,
trigger: 'item',
// position: function (pos) {
// var offsetX = tipsStyle.tooltip.offset[0]; // 水平偏移量
// var offsetY = tipsStyle.tooltip.offset[1]; // 垂直偏移量
// return [pos[0] + offsetX, pos[1] - offsetY];
// },
// axisPointer: {
// type: 'line',
// lineStyle: {
// type: 'solid', // 设置线条类型为实线
// color: tipsStyle.indicator.color, // 设置指示器颜色
// width: tipsStyle.indicator.width // 设置指示器线条宽度
// },
// },
// borderWidth: 0,
// borderColor:"red",
formatter: function (params) {
// 屏蔽边距
if (params.name) {
return '111'
}
return ''
var tipHtml = ''; // 自定义提示框内容
// 标题部分
const titleMes = tipsStyle.categoryLabel
tipHtml += `<div style="
font-weight:${titleMes.textStyle.fontWeight};
font-Family:${titleMes.textStyle.fontFamily};
font-size:${titleMes.textStyle.fontSize}px;
color:${titleMes.textStyle.color};
line-height:${titleMes.textStyle.lineHeight}px;
font-style:${titleMes.textStyle.fontStyle};
text-align:${titleMes.textAlign};
position:relative;
left:${titleMes.offset[0]}px;
top:${titleMes.offset[1]}px
"
>
${params[0].name}
</div>`;
// 数据项部分
const contentLabel = tipsStyle.categoryData.labelStyle
const contentValue = tipsStyle.categoryData.valueStyle
const suffix = tipsStyle.dataSuffix
const suffixStyle = tipsStyle.dataSuffix.textStyle
const iconSize = tipsStyle.categoryData.iconSize
params.forEach(function (item, index) {
// TODO 提示框图标颜色
const temColor = seriesStyle[index].itemStyle.startColor;
var market = `<span style="display:inline-block;margin-right:4px;width:${iconSize}px;height:${iconSize}px;background-color:${temColor};"></span>`
const newValue = retainDecimals(item.value, tipsStyle.categoryData.decimal ?? 0)
tipHtml += `
${market}
<span
style="
font-weight:${contentLabel.fontWeight};
font-Family:${contentLabel.fontFamily};
font-size:${contentLabel.fontSize}px;
color:${contentLabel.color};
line-height:${contentLabel.lineHeight}px;
font-style:${contentLabel.fontStyle};
"
>
${item.seriesName}:
</span>
<span
style="
font-weight:${contentValue.fontWeight};
font-Family:${contentValue.fontFamily};
font-size:${contentValue.fontSize}px;
color:${contentValue.color};
line-height:${contentValue.lineHeight}px;
font-style:${contentValue.fontStyle};
">
${newValue}
</span>`;
if (suffix.name) {
tipHtml += `<span
font-weight:${suffixStyle.fontWeight};
font-Family:${suffixStyle.fontFamily};
font-size:${suffixStyle.fontSize}px;
color:${suffixStyle.color};
line-height:${suffixStyle.lineHeight}px;
font-style:${suffixStyle.fontStyle};
position:relative;
left:${suffix.offset[0]}px;
top:${suffix.offset[1]}px
>${suffix.name}</span><br/>`
} else {
tipHtml += `<br/>`
}
});
tooltipHtml = `<div
style= "
box-sizing: border-box !important;
width:${tipsStyle.tooltip.width}px;
height:${tipsStyle.tooltip.height}px;
padding:${tipsStyle.tooltip.top}px ${tipsStyle.tooltip.right}px ${tipsStyle.tooltip.bottom}px ${tipsStyle.tooltip.left}px
">
${tipHtml}
</div>`
return tooltipHtml;
}
},
// legend: {
// show: data.a('xg.showLenged'),
// icon: "circle",
// orient: "vertical",
// right: "0%",
// top: "20%",
// textStyle: {
// color: data.a('xg.lengedColor'),
// fontSize: data.a('xg.lengedFontSize'),
// },
// formatter: function (params) {
// if (data.a('xg.showLengedValue')) {
// return params + " " + objData[params].value;
// } else {
// return params + " ";
// }
// },
// data: arrName
// },
series: [
{
name: 'Access From',
type: 'pie',
radius: [defaultRingGraph.graphical.radius*100+"%", defaultRingGraph.graphical.outRadius*100+"%"],
data: pieData,
label: {
show: globalStyle?.valueLabel?.show,
color: "#FFF",
formatter: function (params) {
if (params.name) {
let name = params.name
let realValue = params.value
let percentVal = getPercentFun(name)
let suffix = globalStyle.suffixStyle.name
// 真实值 占比值 后缀值 是否存在
let trutyVisible = porpertyShow('global', 'realValue')
let percentVisible = porpertyShow('global', 'percentVal')
let suffixVisible = porpertyShow('global', 'suffix')
let addN = ''
if (globalStyle.valueLabel.layout === 'horizontal') {
addN = ''
} else if (globalStyle.valueLabel.layout === 'vertical') {
addN = '\n'
}
if (!trutyVisible && !percentVisible) {
return `{style1|${params.name}}`
} else if (!trutyVisible && percentVisible) {
return [
`{style1|${name}}`,
`{style4|${percentVal}}`
].join(addN)
// return `{style1|${name}}{style4|${percentVal}}`
} else if (trutyVisible && !percentVisible) {
if (suffixVisible) {
return [
`{style1|${name}:}`,
`{style2|${realValue}}{style3|${suffix}}`
].join(addN)
// return `{style1|${name}}{style2|${realValue}}{style3|${suffix}}`
} else {
return [
`{style1|${name}:}`,
`{style2|${realValue}}`
].join(addN)
// return `{style1|${name}}{style2|${realValue}}`
}
} else if (trutyVisible && percentVisible) {
if (suffixVisible) {
return [
`{style1|${name}:}`,
`{style2|${realValue}}{style3|${suffix}}{style4|(${percentVal})}`
].join(addN)
// return `{style1|${name}}{style2|${realValue}}{style3|${suffix}}{style4|(${percentVal})}`
} else {
return [
`{style1|${name}:}`,
`{style2|${realValue}}{style4|(${percentVal})}`
].join(addN)
// return `{style1|${name}}{style2|${realValue}}{style4|(${percentVal})}`
}
}
return params.name
}
return ''
},
rich: {
style1: {
...globalStyle.categoryStyle.textStyle
},
style2: {
...globalStyle.realValue.textStyle
},
style3: {
fontSize: globalStyle.suffixStyle.fontSize
},
style4: {
...globalStyle.proportionStyle.textStyle
}
},
// fontSize:10
},
labelLine: {
show: globalStyle?.valueLabel?.show,
length: globalStyle?.valueLabel?.labelLine?.length,
length2: globalStyle?.valueLabel?.labelLine?.length2
},
center: ['36%', "50%"],
itemStyle: {
// opacity: 0.2,
// borderWidth:10,
// borderColor:"transparent",
borderRadius: defaultRingGraph.graphical.borderRadius
},
emphasis: {
show: false,
scale: false
}
}
]
};
option1 = {
legend: {
// orient: 'vertical',
// left: 'left',
show: false,
},
series: [
{
name: 'Access From',
type: 'pie',
radius: [defaultRingGraph.decoration.radius*100+"%", defaultRingGraph.decoration.outRadius*100+"%"],
// radius: ['45%', '50%'],
itemStyle: {
// opacity: 0.2,
borderWidth: 10,
borderColor: "transparent"
},
center: ['36%', "50%"],
data: pieData1,
label: {
show: false
},
emphasis: {
show: false,
scale: false
},
}
]
}
// 动画渲染
if (!cache.htmlView) {
cache.htmlView = document.createElement('div');
cache.htmlView.style.position = 'absolute';
cache.htmlView.symbolName = data.getDisplayName() || '基本环图'
/**
* 特殊配置,只针对基本环图功能
*/
cache.kchild0 = document.createElement("div")
cache.kchild1 = document.createElement("div")
cache.htmlView.appendChild(cache.kchild1);
cache.htmlView.appendChild(cache.kchild0);
// let decopacity = defaultRingGraph.decoration.opacity / 100
// let direction = defaultRingGraph.decoration.direction === "CW"? 'rotate-forever':'rotate-forever1'
cache.kchild0.style.cssText = 'position:absolute;zIndex:-10;top:0;left:0;width:100%;height:100%;'
// cache.kchild1.style.cssText = `position:absolute;zIndex:10;top:0;left:0;width:100%;height:100%;opacity:${decopacity};animation: ${direction} 4s linear infinite;transform-origin:36%`
decorationFun()
// cache.kchild0.style.cssText = 'position:absolute;zIndex:-10;top:0;left:0;width:420px;height:210px;'
// cache.kchild1.style.cssText = 'position:absolute;zIndex:10;top:0;left:0;width:420px;height:210px;animation: rotate-forever 2s linear infinite;'
const keyframes = `
@keyframes rotate-forever {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes rotate-forever1 {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
`;
// 获取 style 标签
const styleElement = document.createElement('style');
// 设置 style 元素的 type 属性
styleElement.type = 'text/css';
// 将 keyframes 添加到 style 标签中
if (styleElement.styleSheet) {
// 对于 Firefox
styleElement.styleSheet.cssText = keyframes;
} else {
styleElement.appendChild(document.createTextNode(keyframes));
}
// 获取 head 元素
const head = document.head || document.getElementsByTagName('head')[0];
// 将 style 元素附加到 head 元素
head.appendChild(styleElement);
requestAnimationFrame(() => {
// cache.htmlChart = echarts.init(cache.htmlView);
// cache.htmlChart.setOption(option);
// // 交互配置
// InteractionUtil.AddInteractionEvent(gv.dm(), cache.htmlChart, data)
cache.htmlChart0 = echarts.init(cache.kchild0)
cache.htmlChart0.setOption(option0)
InteractionUtil.AddInteractionEvent(gv.dm(), cache.htmlChart0, data)
cache.htmlChart1 = echarts.init(cache.kchild1)
cache.htmlChart1.setOption(option1)
});
cache.htmlView.layoutHTML = function () {
gv.layoutHTML(data, cache.htmlView, true);
cache.htmlChart && cache.htmlChart.resize();
cache.htmlChart0 && cache.htmlChart0.resize();;
cache.htmlChart1 && cache.htmlChart1.resize();
};
cache.htmlView.onHTMLAdded = function () {
//
}
cache.htmlView.onHTMLRemove = function () {
clearInterval(cache.timer)
}
}
decorationFun()
cache.htmlChart0 && cache.htmlChart0.setOption(option0, true);
cache.htmlChart1 && cache.htmlChart1.setOption(option1, true);
return cache.htmlView;
# 基本折线图
/** 基本折线图 */
var dsValue = data.a('xg.dataValue') || {} // 数据集结果
var seriesData = dsValue['series'] || [];
/**提示框索引*/
var tooltipIndex = 0;
// 全局样式
var defaultGlobalStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.GLOBAL_STYLES), { 'lineStyle': BI.EchartConfig.LINE_STYLES })
var globalStyle = Object.assign(defaultGlobalStyle, data.a('xg.echarts.global'))
const { backgroundColor, grid } = globalStyle;
// 图例
var defaultLegendStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.LEGEND_STYLES))
var legendStyle = Object.assign(defaultLegendStyle, data.a('xg.echarts.legend'))
// console.log('图例:', defaultLegendStyle)
const { icon, itemHeight, itemWidth, layout, textStyle, lengedGap, selectedMode } = legendStyle
// X轴
var defaultXaxisStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.XAXIS_STYLES))
var xaxisStyle = Object.assign(defaultXaxisStyle, data.a('xg.echarts.xAxis'))
const { axisLabel: xAxisLabel, axisLine: xAxisLine, axisTick: xAxisTick, splitLine: xSplitLine } = xaxisStyle;
xAxisLabel.textStyle.lineHeight = 12
copyXAxisLabel = ht.Default.clone(xAxisLabel)
// console.log("defaultXaxisStyle=", defaultXaxisStyle)
// Y轴
var defaultYaxisStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.YAXIS_STYLES))
var yaxisStyle = Object.assign(defaultYaxisStyle, data.a('xg.echarts.yAxis'))
const { axisLabel: yAxisLabel, axisUnit: yAxisUnit, axisLine: yAxisLine, axisTick: yAxisTick, splitLine: ySplitLine } = yaxisStyle;
// const { axisLabel, axisUnit, axisLine, axisTick, splitLine } = defaultYaxisStyle
// console.log("defaultYaxisStyle=", defaultYaxisStyle)
//提示框
var defaultTipsStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.TIPS_STYLE))
var tipsStyle = Object.assign(defaultTipsStyle, data.a('xg.echarts.tips'))
// console.log('提示框信息', tipsStyle)
// 动画 EchartsAnimationView
var defaultAnimationStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.ANIMATION_STYLES), data.a('xg.echarts.animation'))
// console.log('动画', defaultAnimationStyle)
// X轴偏移
xAxisLabel.padding = [xAxisLabel.offset[1] ?? 0, 0, 0, xAxisLabel.offset[0] ?? 0]
// y轴部分处理
// y轴偏移
yAxisLabel.padding = [yAxisLabel.offset[1] ?? 0, 0, 0, yAxisLabel.offset[0] ?? 0]
yAxisLabel.formatter = function (value) {
let newValue = ''
try {
// 小数位
const decimalDigit = yAxisLabel.decimalDigit ?? 0
const suffixContent = yAxisLabel.suffixContent ?? ""
newValue = retainDecimals(value, decimalDigit) + suffixContent
} catch (e) {
newValue = value + suffixContent
}
return newValue
}
// 保留小数函数
function retainDecimals(value, decimalDigit) {
let newValue = ''
const arr = String(value).split(".")
const decimalLen = arr[1]?.length ?? 0
if (decimalDigit === 0) {
newValue = arr[0]
} else if (decimalDigit > decimalLen) {
const len = decimalDigit - decimalLen
const str = "".padStart(len, '0')
const decimalContent = arr[1] ?? ""
newValue = arr[0] + "." + decimalContent + str
}
return newValue
}
var option = {
color: ['rgb(32, 173, 255)', 'rgb(30, 231, 231)'],
backgroundColor: backgroundColor,
grid: Object.assign({
containLabel: true
}, grid),
tooltip: {
show: tipsStyle.hoverTrigger,
backgroundColor: tipsStyle.tooltip.backgroundColor,
padding: [
tipsStyle.tooltip.position.top,
(tipsStyle.tooltip.position.left + tipsStyle.tooltip.position.right) / 2,
tipsStyle.tooltip.position.bottom,
(tipsStyle.tooltip.position.left + tipsStyle.tooltip.position.right) / 2
],
trigger: 'axis',
position: function (pos) {
var offsetX = tipsStyle.tooltip.offset[0]; // 水平偏移量
var offsetY = tipsStyle.tooltip.offset[1]; // 垂直偏移量
return [pos[0] + offsetX, pos[1] - offsetY];
},
axisPointer: {
type: 'line',
lineStyle: {
type: 'solid', // 设置线条类型为实线
color: tipsStyle.indicator.color, // 设置指示器颜色
width: tipsStyle.indicator.width // 设置指示器线条宽度
},
},
borderWidth: 0,
formatter: function (params) {
var tipHtml = ''; // 自定义提示框内容
const titleMes = tipsStyle.categoryLabel
tipHtml += `<div style="
font-weight:${titleMes.textStyle.fontWeight};
font-Family:${titleMes.textStyle.fontFamily};
font-size:${titleMes.textStyle.fontSize}px;
color:${titleMes.textStyle.color};
line-height:${titleMes.textStyle.lineHeight}px;
font-style:${titleMes.textStyle.fontStyle};
text-align:${titleMes.textAlign};
position:relative;
left:${titleMes.offset[0]}px;
top:${titleMes.offset[1]}px
"
>
${params[0].name}
</div>`;
// 数据项部分
const contentLabel = tipsStyle.categoryData.labelStyle
const contentValue = tipsStyle.categoryData.valueStyle
const suffix = tipsStyle.dataSuffix
const suffixStyle = tipsStyle.dataSuffix.textStyle
const iconSize = tipsStyle.categoryData.iconSize
params.forEach(function (item, index) {
const seriesStyle = BI.EchartUtil.getSeriesItemStyle(data, index)
// TODO 提示框图标颜色
const temColor = seriesStyle.lineStyle.color
var market = `<span style="display:inline-block;margin-right:4px;width:${iconSize}px;height:${iconSize}px;background-color:${temColor};"></span>`
const newValue = retainDecimals(item.value, tipsStyle.categoryData.decimal ?? 0)
tipHtml += `
${market}
<span
style="
font-weight:${contentLabel.fontWeight};
font-Family:${contentLabel.fontFamily};
font-size:${contentLabel.fontSize}px;
color:${contentLabel.color};
line-height:${contentLabel.lineHeight}px;
font-style:${contentLabel.fontStyle};
"
>
${item.seriesName}:
</span>
<span
style="
font-weight:${contentValue.fontWeight};
font-Family:${contentValue.fontFamily};
font-size:${contentValue.fontSize}px;
color:${contentValue.color};
line-height:${contentValue.lineHeight}px;
font-style:${contentValue.fontStyle};
">
${newValue}
</span>`;
if (suffix.name) {
tipHtml += `<span
font-weight:${suffixStyle.fontWeight};
font-Family:${suffixStyle.fontFamily};
font-size:${suffixStyle.fontSize}px;
color:${suffixStyle.color};
line-height:${suffixStyle.lineHeight}px;
font-style:${suffixStyle.fontStyle};
position:relative;
left:${suffix.offset[0]}px;
top:${suffix.offset[1]}px
>${suffix.name}</span><br/>`
} else {
tipHtml += `<br/>`
}
});
const tipWidth = tipsStyle.tooltip.width - tipsStyle.tooltip.position.left - tipsStyle.tooltip.position.right
const tipHeight = tipsStyle.tooltip.height - tipsStyle.tooltip.position.top - tipsStyle.tooltip.position.bottom
tooltipHtml = `<div
style= "
width:${tipWidth}px;
height:${tipHeight}px;
">
${tipHtml}
</div>`
return tooltipHtml;
}
},
legend: {
icon: icon, // rect
itemWidth: itemWidth, // 设置宽度
itemHeight: itemHeight, // 设置高度
top: layout.position.top,
left: layout.position.left,
textStyle: Object.assign({
padding: [0, 0, 0, lengedGap]
}, textStyle),
itemGap: layout.itemGap.columnGap,
selectedMode: selectedMode,
show: true,
},
yAxis: [
{
show: defaultYaxisStyle.enabled,
type: 'value',
data: dsValue['xAxis'] || [],
min: yAxisLabel.min,
max: yAxisLabel.max,
axisLabel: Object.assign({ hideOverlap: true }, yAxisLabel),
axisTick: yAxisTick,
boundaryGap: true,
axisLine: yAxisLine,
splitLine: ySplitLine,
}
],
xAxis: [{
show: defaultXaxisStyle.enabled,
type: 'category',
data: dsValue['xAxis'] || [],
axisLabel: copyXAxisLabel,
axisLine: xAxisLine,
axisTick: xAxisTick,
splitLine: xSplitLine,
boundaryGap: ["40%", "10%"],
}],
// dataZoom: [
// {
// show: false,
// xAxisIndex: 0,
// type: 'slider',
// startValue: 0,
// endValue: dsValue['xAxis'].length - 1,
// }
// ],
series: []
};
// 动画渲染
if (!cache.htmlView) {
cache.htmlView = document.createElement('div');
cache.htmlView.style.position = 'absolute';
cache.htmlView.symbolName = data.getDisplayName() || '基本折线图'
requestAnimationFrame(() => {
cache.htmlChart = echarts.init(cache.htmlView);
cache.htmlChart.setOption(option);
cache.htmlChart && addLoopAnimation(cache.htmlChart)
// 交互配置
InteractionUtil.AddInteractionEvent(gv.dm(), cache.htmlChart, data)
});
// 鼠标悬浮
cache.htmlView.onmouseover = function (params) {
cache.mouseIn = true
}
cache.htmlView.onmouseout = function (params) {
cache.mouseIn = false
}
cache.htmlView.layoutHTML = function () {
gv.layoutHTML(data, cache.htmlView, true);
cache.htmlChart && cache.htmlChart.resize();
};
cache.htmlView.onHTMLAdded = function () {
// 绑定你的图例点击事件或其他相关事件
cache.htmlChart.on('legendselectchanged', function (params) {
option.legend.selected = params.selected
cache.htmlChart && cache.htmlChart.setOption(option, true)
});
}
cache.htmlView.onHTMLRemove = function () {
clearInterval(cache.animationTimer)
clearTimeout(cache.tipTimer)
cache.oldAnimationSetting = null
cache.mouseIn = false
cache.labelStyle = null
cache.legendData = null
}
}
if (!cache.oldAnimationSetting) {
cache.oldAnimationSetting = null
}
if (!cache.xAxisLabelInterval && cache.xAxisLabelInterval !== 0) {
cache.xAxisLabelInterval = null
}
// 编辑器修改内容时的动画适配
function changeAnimation() {
// console.warn(cache.xAxisLabelInterval, copyXAxisLabel.interval)
if (cache.xAxisLabelInterval === null) {
cache.xAxisLabelInterval = copyXAxisLabel.interval
} else if (cache.xAxisLabelInterval !== copyXAxisLabel.interval) {
cache.oldAnimationSetting = ht.Default.clone(defaultAnimationStyle)
cache.xAxisLabelInterval = copyXAxisLabel.interval
return true
}
if (cache.oldAnimationSetting === null) {
cache.oldAnimationSetting = ht.Default.clone(defaultAnimationStyle)
return false
} else {
let flag = false
for (let item in defaultAnimationStyle) {
if (defaultAnimationStyle[item] !== cache.oldAnimationSetting[item]) {
cache.oldAnimationSetting = ht.Default.clone(defaultAnimationStyle)
flag = true
break
}
}
return flag
}
}
const haschange = changeAnimation()
if (haschange) {
cache.htmlChart && autoRresh(cache.htmlChart)
}
function addLoopAnimation(myChart) {
// 初始化样式
if (defaultAnimationStyle.enabled) {
autoRresh(myChart);
}
}
function autoRresh(myChart) {
clearInterval(cache.animationTimer)
// TODO 优化
if (xAxisLabel.interval === 0) {
return
}
let startValue = 0;
let len = dsValue['xAxis'].length
let endValue = xAxisLabel.interval ?? len
const xAxisName = ht.Default.clone(dsValue['xAxis'])
const dataVal = ht.Default.clone(seriesData)
// 如果是数量标签少于当前所有的标签才会轮播动画
if ((xAxisLabel.interval < len) && defaultAnimationStyle.enabled) {
copyXAxisLabel.interval = 0
anitmationFun()
function anitmationFun() {
copyXAxisLabel.interval = 0
// 鼠标是否进入
if (cache.mouseIn && defaultAnimationStyle.stopAnimation) {
return
}
if (!defaultAnimationStyle.enabled) {
return clearInterval(cache.animationTimer)
}
// if (endValue === len - 1) {
// endValue = xAxisLabel.interval - 1
// startValue = 0
// option.dataZoom[0].startValue = startValue;
// option.dataZoom[0].endValue = endValue;
// } else {
// if (endValue + 1 >= len) {
// endValue = len - 1
// startValue = len - 1 - xAxisLabel.interval
// } else {
// startValue += 1
// endValue += 1
// }
// option.dataZoom[0].startValue = startValue;
// option.dataZoom[0].endValue = endValue;
// }
xAxisName.push(xAxisName.shift())
option.xAxis[0].data = xAxisName.slice(0, endValue)
if (cache?.legendData?.length) {
option.legend.data = cache.legendData
}
dataVal.forEach((item, index) => {
item.value.push(item.value.shift())
option.series[index].data = item.value.slice(0, endValue)
if (cache.labelStyle) {
// option.series[index] = cache.labelStyle
option.series[index].label = cache.labelStyle[index].label
option.series[index].symbolSize = cache.labelStyle[index].symbolSize
option.series[index].smooth = cache.labelStyle[index].smooth
option.series[index].lineStyle = cache.labelStyle[index].lineStyle
option.series[index].itemStyle = cache.labelStyle[index].itemStyle
option.series[index].name = cache.labelStyle[index].name
}
})
option.xAxis[0].axisLabel = copyXAxisLabel
myChart.setOption(option, true);
if (tipsStyle.autoScroll) {
clearTimeout(cache.tipTimer)
tooltipIndex = startValue
cache.htmlChart?.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: startValue
})
}
}
cache.animationTimer = setInterval(() => {
anitmationFun()
}, defaultAnimationStyle.interval * 1000)
} else if ((xAxisLabel.interval === len) && defaultAnimationStyle.enabled) {
copyXAxisLabel.interval = 0
option.xAxis[0].axisLabel = copyXAxisLabel
myChart.setOption(option, true);
}
}
option.series = [];
option.legend.data = [];
cache.labelStyle = []
cache.legendData = []
seriesData.forEach((item, index) => {
const displayName = BI.EchartUtil.getSeriesDisplayName(data, item, index)
const seriesStyle = BI.EchartUtil.getSeriesItemStyle(data, index)
console.warn('serries', seriesStyle)
const shadowSetting = {}
if (seriesStyle.lineStyle.shadow.enabled) {
shadowSetting.shadowBlur = seriesStyle.lineStyle.shadow.shadowBlur
shadowSetting.shadowColor = seriesStyle.lineStyle.shadow.shadowColor
shadowSetting.shadowOffsetX = seriesStyle.lineStyle.shadow.shadowOffsetY
shadowSetting.shadowOffsetY = seriesStyle.lineStyle.shadow.shadowOffsetY
}
option.legend.data.push({
name: displayName,
itemStyle: {
color: seriesStyle.lineStyle.color
}
});
cache.legendData.push({
name: displayName,
itemStyle: {
color: seriesStyle.lineStyle.color
}
})
const temStyle = {
type: 'line',
name: displayName || '图例1',
data: item.value || item.datas || [],
yAxisIndex: 0,
symbolSize: seriesStyle.lineDataTag.enabled ? seriesStyle.lineDataTag.radius : 0, // 设置折线点的大小
symbol: 'circle',
smooth: seriesStyle.lineStyle.smooth,
label: {
show: seriesStyle.label.show,
formatter: `{style1|{c}}{style2|${seriesStyle.suffix.name}}`,
rich: {
style1: {
...seriesStyle.label.textStyle,
lineHeight: 6,
// transform:translate(seriesStyle.label.offset[0]+'px',seriesStyle.label.offset[1]+'px')
},
style2: {
...seriesStyle.suffix.textStyle,
lineHeight: 6,
// transform:translate(seriesStyle.suffix.offset[0]+'px',seriesStyle.label.offset[1]+'px')
}
},
offset: [seriesStyle.label.offset[0], seriesStyle.label.offset[1]]
},
lineStyle: {
type: seriesStyle.lineStyle.type,
width: seriesStyle.lineStyle.width,
color: seriesStyle.lineStyle.color,
curveness: seriesStyle.lineStyle.smoothStrain,
...shadowSetting
},
itemStyle: {
color: seriesStyle.lineDataTag.color
}
}
cache.labelStyle.push(temStyle)
option.series[index] = {
// type: 'line',
// name: displayName || '图例1',
// data: item.value || item.datas || [],
// yAxisIndex: 0,
// symbolSize: seriesStyle.lineDataTag.enabled ? seriesStyle.lineDataTag.radius :0, // 设置折线点的大小
// symbol: 'circle',
// smooth: seriesStyle.lineStyle.smooth,
...temStyle
};
});
// TODO x轴部分操作
// // 针对x轴的部分操作
// function xAxisFun() {
// const { interval, offset, rotate, show, textStyle, timeFormatter, type } = xAxisLabel
// // option.xAxis[0].offset =offset
// option.xAxis[0].rotate = rotate
// option.xAxis[0].show = show
// option.xAxis[0].textStyle = textStyle
// option.xAxis[0].timeFormatter = timeFormatter
// option.xAxis[0].type = type
// // 这里去控制标签数量 - 结合interval
// const dataLen = dsValue.xAxis.length;
// if (interval === 0) {
// option.xAxis[0].data = dsValue.xAxis
// console.log(1, option.xAxis[0].data)
// } else if (interval <= 2) {
// option.xAxis[0].data = new Array(dataLen).fill('')
// option.xAxis[0].data[0] = dsValue.xAxis[0]
// option.xAxis[0].data[dataLen - 1] = dsValue.xAxis[dataLen - 1]
// console.log(2, option.xAxis[0].data)
// } else if (dataLen % interval === 0) {
// } else {
// }
// }
// xAxisFun()
cache.htmlChart && cache.htmlChart.setOption(option, true);
// 没有轮播
let otherConditions = false
if (!defaultAnimationStyle.enabled || (defaultAnimationStyle.enabled && copyXAxisLabel.interval === 0)) {
otherConditions = true
}
if (tipsStyle.autoScroll && otherConditions) {
tooltipLoop()
} else {
clearTimeout(cache.tipTimer)
}
function tooltipLoop() {
clearTimeout(cache.tipTimer)
cache.htmlChart?.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: tooltipIndex
})
tooltipIndex = (tooltipIndex + 1) % option.series[0].data.length
cache.tipTimer = setTimeout(tooltipLoop, 4000)
}
return cache.htmlView;
# 预测面积图
/** 基本折线图 */
var dsValue = data.a('xg.dataValue') || {} // 数据集结果
console.log(dsValue)
const seriesDataArr = []
const dsArrLen = dsValue.series[0]?.value?.length ?? 0
const xAxisNameArr = dsValue.xAxis
getData(dsValue.series[0].value, 0, 0, true)
//操作数组 数组下标 seriesDataArr数组下标 是否是子数组的第一位
function getData(arr, index, arridx, flag) {
if (index + 1 > dsArrLen - 1) return
if (flag) {
seriesDataArr[arridx] = [arr[index]]
seriesDataArr[arridx] = [[xAxisNameArr[index], arr[index].value]]
seriesDataArr[arridx].predict = arr[index].predict
getData(arr, index, arridx, false)
} else if (arr[index].predict === arr[index + 1].predict) {
// seriesDataArr[arridx].push(arr[index + 1])
seriesDataArr[arridx].push([xAxisNameArr[index + 1], arr[index + 1].value])
getData(arr, index + 1, arridx, false)
} else {
const lastArrBottom = seriesDataArr[arridx][seriesDataArr[arridx].length - 1]
// seriesDataArr[arridx + 1] = [val, arr[index + 1]]
seriesDataArr[arridx + 1] = [lastArrBottom, [xAxisNameArr[index + 1], arr[index + 1].value]]
seriesDataArr[arridx + 1].predict = arr[index + 1].predict
getData(arr, index + 1, arridx + 1, false)
}
}
console.log('seriesDataArr', seriesDataArr)
// 全局样式
var defaultGlobalStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.GLOBAL_STYLES))
var globalStyle = Object.assign(defaultGlobalStyle, data.a('xg.echarts.global'))
const { backgroundColor, grid } = globalStyle;
// 图例
var defaultLegendStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.LEGEND_STYLES))
var legendStyle = Object.assign(defaultLegendStyle, data.a('xg.echarts.legend'))
// console.log('图例:', defaultLegendStyle)
const { icon, itemHeight, itemWidth, layout, textStyle, lengedGap, selectedMode } = defaultLegendStyle
// X轴
var defaultXaxisStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.XAXIS_STYLES))
var xaxisStyle = Object.assign(defaultXaxisStyle, data.a('xg.echarts.xAxis'))
const { axisLabel: xAxisLabel, axisLine: xAxisLine, axisTick: xAxisTick, splitLine: xSplitLine } = defaultXaxisStyle;
console.log("defaultXaxisStyle=", defaultXaxisStyle)
// X轴偏移
xAxisLabel.padding = [xAxisLabel.offset[1] ?? 0, 0, 0, xAxisLabel.offset[0] ?? 0]
xAxisLabel.textStyle.lineHeight = 12
// Y轴
var defaultYaxisStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.YAXIS_STYLES))
var yaxisStyle = Object.assign(defaultYaxisStyle, data.a('xg.echarts.yAxis'))
const { axisLabel: yAxisLabel, axisUnit: yAxisUnit, axisLine: yAxisLine, axisTick: yAxisTick, splitLine: ySplitLine } = defaultYaxisStyle;
// const { axisLabel, axisUnit, axisLine, axisTick, splitLine } = defaultYaxisStyle
console.log("defaultYaxisStyle=", defaultYaxisStyle)
console.log(BI.EchartConfig.YAXIS_STYLES)
console.log("-----")
// 系列 BI.EchartConfig.SERIES_STYLES
let defaultSeriesStyle = Object.assign({}, ht.Default.clone(BI.EchartConfig.SERIES_STYLES))
let seriesStyle = Object.assign(defaultSeriesStyle, data.a('xg.echarts.series'))
console.log(seriesStyle)
var option = {
color: ['rgba(42,157,255,1)', 'rgb(30, 231, 231)'],
backgroundColor: backgroundColor,
grid: Object.assign({
containLabel: true
}, grid),
tooltip: {
show: false,
trigger: 'axis',
axisPointer: {
type: 'line',
lineStyle: {
color: '#ffa147',
width: 1,
type: 'dashed'
}
}
},
legend: {
icon: icon, // rect
itemWidth: itemWidth, // 设置宽度
itemHeight: itemHeight, // 设置高度
top: layout.position.top,
left: layout.position.left,
textStyle: Object.assign({
padding: [0, 0, 0, lengedGap]
}, textStyle),
itemGap: layout.itemGap.columnGap,
selectedMode: selectedMode,
show: true,
data:['Data1']
},
yAxis: [
{
show: defaultYaxisStyle.enabled,
type: 'value',
// data: dsValue['xAxis'] || [], //['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLabel: yAxisLabel,
axisTick: yAxisTick,
boundaryGap: true,
axisLine: Object.assign({
inside: true,
hideOverlap:true
}, yAxisLine),
splitLine: ySplitLine
}
],
xAxis: [{
show: defaultXaxisStyle.enabled,
type: 'category',
data: xAxisNameArr ?? [],
// min: yAxisLabel.min,
// max: yAxisLabel.max,
// splitNumber: 4,
axisLabel: xAxisLabel,
axisLine: xAxisLine,
axisTick: xAxisTick,
splitLine: xSplitLine,
}],
series: []
};
// 动画渲染
if (!cache.htmlView) {
cache.htmlView = document.createElement('div');
cache.htmlView.style.position = 'absolute';
cache.htmlView.symbolName = data.getDisplayName() || '预测面积图'
requestAnimationFrame(() => {
cache.htmlChart = echarts.init(cache.htmlView);
cache.htmlChart.setOption(option);
// 交互配置
InteractionUtil.AddInteractionEvent(gv.dm(), cache.htmlChart, data)
});
cache.htmlView.layoutHTML = function () {
gv.layoutHTML(data, cache.htmlView, true);
cache.htmlChart && cache.htmlChart.resize();
};
}
var seriesData = dsValue['series'] || [];
option.series = [];
option.legend.data.push('图例1');
// 这里需要去区分 实际和预测的两种方式不同的呈现
seriesDataArr.forEach((item, idx) => {
if (!item.predict) {
option.series.push({
name: 'Data1',
type: 'line',
showSymbol: false,
data: item,
areaStyle: {
origin:"start",
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: 'rgba(42,157,255,1)'
},
{
offset: 0,
color: 'rgba(42,157,255,0.8)'
}
])
},
lineStyle: {
width: 1,
color: "rgba(42,157,255,1)",
}
})
} else {
option.series.push({
name: 'Data2' + idx,
type: 'line',
showSymbol: false,
lineStyle: {
type: 'dashed',
width: 1,
color: "rgba(255, 255, 255, 1)",
},
// symbol: 'none',
data: item,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(255, 255, 255, 0.8)'
},
{
offset: 1,
color: 'rgba(255, 255, 255,8e-05)'
}
])
}
})
}
})
console.log(option.series)
cache.htmlChart && cache.htmlChart.setOption(option, true);
return cache.htmlView;