|
|
const e="d772ad91-66dd-434d-8044-4e99d126c1cb",n="custom-3d-circle-pie",t="3d立体环形图",a='<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1697505891514" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22469" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M485.179 112.66c-233.873 0-423.464 189.591-423.464 423.464s189.591 423.464 423.464 423.464 423.464-189.591 423.464-423.464S719.052 112.66 485.179 112.66z m0 712.663c-159.72 0-289.199-129.479-289.199-289.199s129.479-289.199 289.199-289.199 289.199 129.479 289.199 289.199-129.479 289.199-289.199 289.199z" fill="#0CA294" p-id="22470"></path><path d="M711.686 536.125h248.512c-0.148-261.822-212.44-474.024-474.296-474.024v248.51c124.608 0 225.636 100.941 225.784 225.514z" fill="#D73949" p-id="22471"></path></svg>',i="svg",o="动态",l="图表组件",p=!1,c=!0,r="时间",s=`{"type":"page","id":"u:270584784ce1","name":"page1","asideResizor":false,"style":{"boxShadow":" 0px 0px 0px 0px transparent"},"pullRefresh":{"disabled":true},"body":[{"type":"tabs","name":"tab","tabs":[{"title":"样式","icon":"fa fa-th-large","body":[{"type":"form","title":"","name":"basicPropForm","body":[{"type":"input-text","label":"名称","name":"nodeAlias","id":"u:6b126f0520cb","size":"full","mode":"horizontal","inputControlClassName":"w-100","className":"m-b"},{"type":"input-text","label":"ID ","name":"id","id":"u:6232710ac003","size":"full","mode":"horizontal","inputControlClassName":"w-100","className":"m-b"},{"type":"grid","id":"u:c605398a724c","className":"m-b","columns":[{"body":[{"type":"input-number","label":"宽度","name":"width","keyboard":true,"id":"u:dcc0c21d16f6","step":1,"suffix":"px","placeholder":"组件左边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:14cc19d6ffb0","md":6},{"body":[{"type":"input-number","label":"高度","name":"height","keyboard":true,"id":"u:cd6fdff9ca88","step":1,"suffix":"px","placeholder":"组件上边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:4931801ca9b8","md":6}]},{"type":"grid","id":"u:da449a94908a","className":"m-b","columns":[{"body":[{"type":"input-number","label":"X 轴","name":"x","keyboard":true,"id":"u:29852d093d9d","step":1,"suffix":"px","placeholder":"组件左边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:1b561d652acc","md":6},{"body":[{"type":"input-number","label":"Y 轴","name":"y","keyboard":true,"id":"u:dc8c1daed8ed","step":1,"suffix":"px","placeholder":"组件上边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:9672575193ac","md":6}]},{"type":"grid","id":"u:a332a7bf83c1","className":"m-b","columns":[{"body":[{"type":"input-number","label":"旋转","name":"rotation","id":"u:f6a2dbb518f9","placeholder":"组件旋转角度","mode":"horizontal","size":"full","className":"","keyboard":true,"step":1,"suffix":"deg","value":0,"labelAlign":"left","inputClassName":"w-full"}],"id":"u:646cd98b7955","md":6},{"body":[{"type":"input-number","label":"透明","name":"opacity","id":"u:cf80f59d8d42","placeholder":"组件透明度","mode":"horizontal","size":"full","className":"m-b","keyboard":true,"step":0,"suffix":"","value":1,"inputClassName":"w-full","precision":2}],"id":"u:51ddf54ac749","md":6}],"gap":""},{"type":"grid","columns":[],"id":"u:235f153e5ad5","className":"m-b"},{"type":"grid","columns":[{"body":[{"type":"input-color","label":"图例颜色","name":"legendFontColor","id":"u:dcdc031da477","format":"hex","mode":"horizontal","inputClassName":"w-full myColorPick"}],"id":"u:656bda4e655b"},{"body
"nodes": [ { "id": "4b101b77-1d42-4894-8776-a3bbc4fa219f", "type": "custom-3d-circle-pie", "x": 200, "y": 200, "text": { "value": "", "x": 200, "y": 200 }, "properties": { "id": "4b101b77-1d42-4894-8776-a3bbc4fa219f", "width": 420, "height": 200, "x": 200, "y": 200, "rotation": 0, "opacity": 1, "codeConfig": "return option;", "nodeAlias": "3d立体环形图", "showDefaultValue": false, "showUnit": false, "valueColor": "rgba(245, 166, 35, 1)", "fontSize": 12, "legendFontColor": "#50e3c2", "labelTextColor": "#50e3c2", "unit": "kWh", "itemColors": [ { "ratio": 0, "color": "#F6B54A" }, { "color": "#CB5003" }, { "color": "#0375AA" }, { "color": "#8FC31F" }, { "color": "#29ee92" } ], "tooltip": { "borderColor": "rgba(0, 141, 255, 0.6)", "backgroundColor": "rgba(70,94,144,0.6)", "style": { "color": "rgba(255, 255, 255, 1)" }, "borderWidth": 1, "borderRadius": 6 }, "dynamic": { "normalData": { "dataPoint": "", "compareType": "", "conditionVariables": [], "defaultValue": "", "unit": "", "renderIntervalEnabled": true, "legendNameType": "attrName", "dataShowTypes": "oneThingOneAttr" } } } } ]}`,javascript:`const { createApp, createVNode, render } = Vue;const app = createApp({})
const macaronColors = [ "#FFC0CB", // 粉红色
"#FFF44F", // 柠檬黄色
"#87CEEB", // 天蓝色
"#8A2BE2", // 紫罗兰色
"#FFA500", // 橙色
"#8DB600", // 绿苹果色
"#FF007F", // 玫瑰红色
"#9400D3", // 深紫色
"#32CD32", // 青柠绿色
"#FF9A8A", // 桃红色
"#00008B", // 深蓝色
"#20B2AA", // 青绿色
"#8B0000", // 深红色
"#32CD9A", // 柠檬绿色
"#E6E6FA", // 浅紫色
"#FF7F50", // 珊瑚橙色
"#90EE90", // 浅绿色
"#ADD8E6", // 浅蓝色
"#FFDAB9", // 桃红色
"#800080" // 紫色
];
const defaultSocketValue = [];
let myChart = null;
// 修改3d饼图绘制过程
var each = Highcharts.each, round = Math.round, cos = Math.cos, sin = Math.sin, deg2rad = Math.deg2rad;Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, "translate", function (proceed) { proceed.apply(this, [].slice.call(arguments, 1)); // Do not do this if the chart is not 3D
if (!this.chart.is3d()) { return; } // 如果是右边当月用能占比饼图,则不执行此操作。
if (this.chart.container.closest(".pie-3d-container")) { return; } let chart = this.chart, options = chart.options, seriesOptions = this.options, depth = seriesOptions.depth || 0, options3d = options.chart.options3d, alpha = options3d.alpha, beta = options3d.beta, z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : this._i * depth; z += depth / 2; if (seriesOptions.grouping !== false) { z = 0; } var series = this.center; each(this.data, function (point) { var shapeArgs = point.shapeArgs, angle; point.shapeType = "arc3d"; var ran = point.options.h; shapeArgs.z = z; shapeArgs.depth = depth * 0.75 + ran; shapeArgs.alpha = alpha; shapeArgs.beta = beta; shapeArgs.center = series; shapeArgs.ran = ran; angle = (shapeArgs.end + shapeArgs.start) / 2; point.slicedTranslation = { translateX: round(cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)), translateY: round(sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)) }; });});(function (H) { H.wrap(Highcharts.SVGRenderer.prototype, "arc3dPath", function (proceed) { // Run original proceed method
var ret = proceed.apply(this, [].slice.call(arguments, 1)); ret.zTop = (ret.zOut + 0.5) / 100; return ret; });})(Highcharts);
// 图例格式化
const assembleLegend = (api, thingKey, attrkey, dataShowTypes, legendNameType, datas) => { if (api) { const infos = window.totalDeviceInfos[api]; const thing = infos[datas[0].thingCode]; const thingName = thing.entityName; const attrName = thing.attrs[attrkey].name; if (dataShowTypes.value === 'oneThingOneAttr') { switch (legendNameType.value) { case "thingName": return thing.entityName; case "thingCode": return thingKey; case "attrName": return attrName; case "attrCode": return attrkey; case "thingNameAttrName": return thingName + '-' + attrName; case "thingCodeAttrCode": return thingKey + '-' + attrkey; } } else if (dataShowTypes.value === 'oneThingManyAttr') { switch (legendNameType.value) { case "attrName": return thing.attrs[attrkey].name; case "attrCode": return attrkey; case "thingNameAttrName": return thingName + '-' + attrName; case "thingCodeAttrCode": return thingKey + '-' + thingKey } } else if (dataShowTypes.value === 'manyThingManyAttr') { switch (legendNameType.value) { case "thingNameAttrName": const attrName = thing.attrs[attrKey].name return thingName + '-' + attrName; case "thingCodeAttrCode": return thingKey + '-' + thingKey; } } else if (dataShowTypes.value === 'manyThingOneAttr') { switch (legendNameType.value) { case "thingName": return thingName; case "thingCode": return thingKey; case "thingNameAttrName": const attrName = thing.attrs[attrKey].name return thingName + '-' + attrName; case "thingCodeAttrCode": return thingKey + '-' + thingKey; } } } else { return attrkey; }}
const PieChartCircle3D = { template: '<div :id="lineId" :style="getStyle" class="highcharts-wrapper pie-3d-circle-chart"></div>', props: { lineId: { type: String, default: '' }, historyDatas: { type: Array, default: () => [] }, width: { type: Number, default: 350 }, height: { type: Number, default: 150 }, codeConfig: { type: String, default: '' }, legendFontColor: { type: String, default: '' }, labelTextColor: { type: String, default: '' }, valueColor: { type: String, default: '' }, unit: { type: String, default: '' }, dataShowTypes: { type: String, default: 'oneThingManyAttr', }, legendNameType: { type: String, default: 'attrName', }, apiid: { type: String, default: '', }, itemColors: { type: Array, default: () => [ { "ratio": 0, "color": "#F6B54A" }, { "color": "#CB5003" }, { "color": "#0375AA" }, { "color": "#8FC31F" }, { "color": "#29ee92" } ] }, tooltip: { type: Object, default: () => ({ backgroundColor: "rgba(70,94,144,0.6)", borderColor: "rgba(0, 141, 255, 0.6)", borderRadius: 6, borderWidth: 1, style: { color: "#fff" } }) } }, computed: { getStyle() { return { width: \`\${this.width}px\`,
height: \`\${this.height}px\`
} } }, setup(props) { const { onMounted, nextTick, toRefs, watch } = Vue; const { historyDatas, codeConfig, dataShowTypes, legendNameType, apiid, itemColors, tooltip, unit } = toRefs(props);
const initChart = (datas) => { // 基于准备好的dom,初始化echarts实例
const dom = document.getElementById(props.lineId); if (dom) { if (myChart) { myChart.destroy(); myChart = null; } if (datas) { let totalDatas = []; let totalAmount = 0; let legends = []; if (datas.length > 0) { const thingGrouped = window._.groupBy(datas, 'thingCode'); for (const thingKey in thingGrouped) { const attrGrouped = window._.groupBy(thingGrouped[thingKey], 'attrKey') for (const key in attrGrouped) { let serieData = attrGrouped[key]; const legendKey = assembleLegend(apiid.value, thingKey, key, dataShowTypes, legendNameType, serieData); legends.push(legendKey); totalDatas.push({ name: legendKey, h: 0, y: Number(serieData[0].val), bfb: 0, unit: unit.value }); totalAmount += Number(serieData[0].val); } } totalDatas = totalDatas.map(i => { i.h = Number(((i.y / totalAmount) * 100).toFixed(0)); return i; }) } else { totalDatas = [ { name: "红草莓", y: 10254, h: 30, bfb: 0 }, { name: "白草莓", y: 6894, h: 18, bfb: 0 }, { name: "红颜草莓", y: 7667, h: 20, bfb: 0 }, { name: "甜宝草莓", y: 4287, h: 12, bfb: 0 }, ] }
const serieColors = itemColors.value.concat(macaronColors).map(i => { return { // 注意!!!如果是柱状图请使用color,如果是面积图请使用fillColor
linearGradient: { x1: 0, y1: 1, x2: 1, y2: 0 }, stops: [ [0, i.color || i], [1, i.color || i] ] } })
// 指定图表的配置项和数据
var option = { chart: { type: "pie", accessibility: { enabled: false }, reflow: true, backgroundColor: "rgba(0, 0, 0, 0)", events: { load: function () { const each = Highcharts.each; const points = this.series[0].points; each(points, function (p, i) { p.graphic.attr({ translateY: -p.shapeArgs.ran }); p.graphic.side1.attr({ translateY: -p.shapeArgs.ran }); p.graphic.side2.attr({ translateY: -p.shapeArgs.ran }); }); } }, options3d: { enabled: true, alpha: 65, beta: 0 } }, navigation: { align: 'right' }, legend: { enabled: false, layout: 'horizontal', itemHoverStyle: { color: "#34dcfc" }, symbolWidth: 16, symbolHeight: 14, symbolRadius: 3, }, tooltip: { animation: true, formatter: function () { return \`<span style="color:\${tooltip.value.style.color}">\${this.point.name} : \${this.point.y} </span>\`;
}, // pointFormat: \`<b>{series.name}: {point.percentage:.1f}%</b>\`,
...tooltip.value }, exporting: { enabled: false }, credits: { enabled: false }, title: { show: "false", text: "" }, subtitle: { text: "" }, plotOptions: { pie: { depth: 35, allowPointSelect: false, cursor: "pointer", innerSize: 68, size: "85%", dataLabels: { enabled: true, // format: \`<b>{point.name}</b> + <b style='color: #ffffff'>{point.percentage:.1f} %</b><\\n><\`,
formatter: function () { return \`<span style='color: \${props.labelTextColor};font-size:12px;'>\${this.point.name} </span><span style='color: \${props.valueColor};font-size:12px;'>\${this.point.y} \${unit.value}</span>\`;
// return "<span style='color: #ffffff'>" + this.point.name + "</span> " + "<span style='color: #2B95CC'>" + this.percentage.toFixed(2) + "%</span>";
}, connectorColor: "#02AAD0", style: { textOverflow: "ellipsis", textOutline: "none" } }, // 显示图例
showInLegend: true } }, series: [ { type: "pie", name: "", colorByPoint: true, // h 是高度 y是占的圆环长度
colors: serieColors, data: totalDatas } ] };
const func = new Function('option', 'datas', codeConfig.value); const opt = func(window._.cloneDeep(option), datas); // 使用刚指定的配置项和数据显示图表。
nextTick(() => { myChart = Highcharts.chart(props.lineId, opt); myChart.unit = props.unit; Highcharts.addEvent(myChart, "redraw", function () { var each = Highcharts.each; const points = myChart.series[0].points; each(points, function (p, i) { // if (i !== 1 && i !== 2) {
p.graphic.attr({ translateY: -p.shapeArgs.ran }); p.graphic.side1.attr({ translateY: -p.shapeArgs.ran }); p.graphic.side2.attr({ translateY: -p.shapeArgs.ran }); }); setTimeout(() => { document.querySelector('.highcharts-scrollable-legend .highcharts-legend').setAttribute('transform', 'translate(0,0)'); }, 1000) }); myChart.reflow();
setTimeout(() => { // 手动创建横向的滚动图例
const frags = document.createDocumentFragment(); totalDatas.forEach((i, index) => { const div = document.createElement('div'); div.style = 'display: inline-block; margin-right: 10px;'; const span = document.createElement('span'); const color = serieColors[index].stops[0][1]; span.style = \`display: inline-block;width: 12px; height: 12px; background-color: \${color}; border-radius: 2px; margin-right: 3px;\`;
const span2 = document.createElement('span'); span2.style = \`color: \${props.legendFontColor}\`;
span2.innerHTML = i.name; div.appendChild(span); div.appendChild(span2); frags.appendChild(div) }) const wrapper = document.createElement('div'); wrapper.className = "my-highcharts-legend-wrapper" wrapper.style = "position: absolute; bottom: 0; left: 0; righit: 0; width: 100%; height: 16px; display: block; overflow-x: auto; overflow: hidden; padding: 0 32px 0px 16px; box-sizing: border-box;"; const inner = document.createElement('div'); inner.style = 'display: inline-block; width: max-content;'; inner.className = 'my-highcharts-legend-inner'; inner.appendChild(frags); wrapper.appendChild(inner);
setTimeout(() => { if (wrapper.offsetWidth < inner.offsetWidth) { // 左箭头
const leftArrow = document.createElement('span'); leftArrow.style = \` position: absolute;
left: 2px; top: 2px; display: inline-block; width:8px; height: 8px; border-right: 2px solid \${props.legendFontColor}; border-bottom: 2px solid \${props.legendFontColor}; -webkit-transform: rotate(135deg);cursor: pointer;\`
const rightArrow = document.createElement('span'); rightArrow.style = \`position: absolute;
right: 2px; top: 2px; display: inline-block; width:8px; height: 8px; border-right: 2px solid \${props.legendFontColor}; border-bottom: 2px solid \${props.legendFontColor}; -webkit-transform: rotate(-45deg);cursor: pointer\`;
wrapper.appendChild(leftArrow); wrapper.appendChild(rightArrow);
let translation = 0; const prev = () => { if (translation >= 0) { return; } else { translation += 20; inner.style.transform = \`translateX(\${translation}px)\`;
} } const next = () => { if (inner.offsetWidth - wrapper.offsetWidth <= Math.abs(translation)) { return; } else { translation -= 20; inner.style.transform = \`translateX(\${translation}px)\`;
} } leftArrow.addEventListener('click', prev); rightArrow.addEventListener('click', next); } }, 500) const compWrapper = document.getElementById(props.lineId); compWrapper.style.position = 'relative'; compWrapper.appendChild(wrapper); }) }) } } }
watch(historyDatas, (val) => { if (val) { nextTick(() => { initChart(val); }) } }, { immediate: true }) }}
class Custom3DPieCircleNode extends HtmlResize.view { chartRendered = false historyDatas = [] oldProperties = {}
setHtml(rootEl) { if (!rootEl) return; const { properties, width, height, } = this.props.model; const { nodeAlias, grid, title, legend, tooltip, xAxis, yAxis, codeConfig, legendFontColor, labelTextColor, valueColor, unit, apiid, itemColors } = properties; const { normalData } = properties.dynamic || {}; const { dataShowTypes, legendNameType } = normalData || {};
const el = document.createElement('div'); rootEl.innerHTML = ''; const instance = createVNode(PieChartCircle3D, { name: nodeAlias, lineId: \`line-\${properties.id}\`,
historyDatas: this.historyDatas, width, height, grid, title, legend, tooltip, xAxis, yAxis, codeConfig, legendFontColor, labelTextColor, valueColor, unit, dataShowTypes, legendNameType, apiid, itemColors, tooltip, }) instance.appContext = app._context render(instance, el) rootEl.appendChild(el); }
sameProps(properties) { const isSame = window._.isEqual(this.oldProperties, properties); if (isSame) return true; this.oldProperties = properties; return false }
filterHistoryData(thingCodeArr, dataPointArr, apiid, renderIntervalEnabled) { if (dataPointArr && dataPointArr.length > 0) { let datas = [] if (renderIntervalEnabled) { datas = window.totalHistoryDatas[apiid]; } else { if (window.globalDashboardDatas[apiid]) { datas = window.globalDashboardDatas[apiid].values; } } if (datas && datas.length > 0) { const gotValues = datas.filter((val) => thingCodeArr.includes(val.thingCode) && dataPointArr.includes(val.attrKey)) this.historyDatas = gotValues this.chartRendered = true; } } }
// 生命周期 支持重写内容, 但格式需一致
shouldUpdate() { const { properties } = this.props.model; const { apiid } = properties; const { normalData } = properties.dynamic || {}; const { thingCodeArr, dataPointArr, defaultValue } = normalData || {}
if (normalData && !normalData.dataPoint && !normalData.defaultValue) { this.historyDatas = defaultSocketValue; return true } else if (normalData && !normalData.dataPoint && normalData.defaultValue) { this.historyDatas = JSON.parse(defaultValue); return true }
const propertiesBack = window._.cloneDeep(properties); if (propertiesBack.dynamic.normalData) { propertiesBack.dynamic.normalData.defaultValue = ''; if (this.sameProps(propertiesBack) && this.chartRendered) { return false } if (dataPointArr && apiid && !this.chartRendered) { this.filterHistoryData(thingCodeArr, dataPointArr, apiid, normalData.renderIntervalEnabled); return true; } } return true; }
updateHtml() { this.setHtml(this.rootEl); }
componentDidMount() { const { properties } = this.props.model; const { normalData } = properties.dynamic || {}; const { renderInterval, dataPointArr, thingCodeArr } = normalData || {}; if (this.shouldUpdate()) { this.setHtml(this.rootEl); }
const initRender = () => { // 第一次历史数据返回可能比较慢,轮询判断
let times = 0 const inter = setInterval(() => { if (window.totalHistoryDatas && window.totalHistoryDatas[properties.apiid]) { this.filterHistoryData(thingCodeArr, dataPointArr, properties.apiid, normalData.renderIntervalEnabled); this.setHtml(this.rootEl); clearInterval(inter); } if (times > 20) { clearInterval(inter) } times++; }, 1000) } initRender();
let inters = parseInt(renderInterval || '300000') if (normalData && !normalData.renderIntervalEnabled) { inters = 1000 } setInterval(() => { if (window.totalHistoryDatas[properties.apiid]) { this.filterHistoryData(thingCodeArr, dataPointArr, properties.apiid, normalData.renderIntervalEnabled); this.setHtml(this.rootEl); } }, inters) // 防止拖动时候频繁渲染图表
this.updateHtmlDebounced = window._.debounce(this.updateHtml.bind(this), 500); }
componentDidUpdate() { if (this.shouldUpdate()) { this.updateHtmlDebounced(); } }}
class Custom3DPieCircleModel extends HtmlResize.model { initNodeData(data) { // 自定义组件,需最开始重置一下text 。
data.text = { value: "", x: data.x, y: data.y, };
super.initNodeData(data); const { properties } = this; this.width = properties.width || 80; this.height = properties.height || 35; this.text.editable = false; // 不允许文本被编辑
}
setAttributes() { // 自定义组件需重置 text
const { x, y, properties } = this; const { textHorizontalMove = 0, textVerticalMove = 0 } = properties; this.text = { ...this.text, x: x + textHorizontalMove, y: y + textVerticalMove, value: "", } }}
lf.register({ type: 'custom-3d-circle-pie', view: Custom3DPieCircleNode, model: Custom3DPieCircleModel,})`,css:`.pie-3d-circle-chart .highcharts-root {\r stroke: none;\r}\r.highcharts-legend {\r overflow-y: hidden !important;\r}`,fakeData:""},u={id:e,name:n,aliasName:t,image:a,imageType:i,groupName:o,groupType:l,isRemote:!1,isDefault:!0,sectionType:r,config:s,files:d};export{t as aliasName,s as config,u as default,d as files,o as groupName,l as groupType,e as id,a as image,i as imageType,c as isDefault,p as isRemote,n as name,r as sectionType};
|