|
|
const t="9c0df275-0475-400d-8ab1-7ce0193ee19b",e="custom-therm-waterfill-node",a="温度计水球图",n="data:image/jpeg;base64,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 "nodes": [ { "id": "8ab9a2bf-f570-469f-a9a7-dbc62168d0a9", "type": "custom-therm-waterfill-node", "x": 200, "y": 200, "text": { "value": "", "x": 200, "y": 200 }, "properties": { "id": "8ab9a2bf-f570-469f-a9a7-dbc62168d0a9", "width": 200, "height": 200, "x": 200, "y": 200, "rotation": 0, "opacity": 1, "codeConfig": "return option", "outline": { "show": false }, "nodeAlias": "简单温度计水球图", "showDefaultValue": false, "showUnit": false, "valueColor": "rgba(245, 166, 35, 1)", "fontSize": 12, "Waves": [ { "color": "#8bf707" } ], "waterFillShape": "circle", "backgroundStyle": { "color": "rgba(255, 255, 255, 0.1)", "borderColor": "rgba(74, 144, 226, 1)", "borderWidth": 3, "shadowBlur": 10, "shadowColor": "rgba(155, 155, 155, 0.1)" }, "maxValue": 100, "title": { "text": "温度", "textStyle": { "color": "#4A90E2", "fontSize": 18 }, "subtextStyle": { "color": "#0A5DBF", "fontSize": 16 } }, "minValue": 0, "warnValue": 70, "seriousValue": 85, "dynamic": { "normalData": { "dataPoint": "", "compareType": "", "conditionVariables": [], "defaultValue": "", "unit": "" } } } } ]}`,javascript:`const { createApp, createVNode, render } = Vue;const app = createApp({})
const defaultVal = 62.3;
const ThermWaterFill = { template: '<div :id="chartId" :style="getStyle"></div>', props: { chartId: { type: String, default: '' }, currentData: { type: Number, default: 100 }, width: { type: Number, default: 350 }, height: { type: Number, default: 150 }, chartProps: { type: Object, default: () => { } }, thingName: { type: String, default: '' }, attr: { type: String, default: '' }, unit: { type: String, default: '' }, }, computed: { getStyle() { return { width: \`\${this.width}px\`,
height: \`\${this.height}px\`
} } }, setup(props) { const { onMounted, nextTick, toRefs, watch } = Vue; const { chartProps, currentData, thingName, attr, width, height } = toRefs(props);
let myChart = null; const initChart = (data, pros) => { // 基于准备好的dom,初始化echarts实例
const dom = document.getElementById(props.chartId); if (dom) { if (!myChart) { myChart = echarts.init(dom); } // 由于实时推送时候不会重复创建实例,但是需更新画布大小。
myChart.resize({ width: width.value, height: height.value, }) if (data != null) { const { codeConfig, Waves, waterFillShape, backgroundStyle, outline, maxValue, title, minValue, warnValue, seriousValue } = pros; // 指定图表的配置项和数据
var temperature = (+data).toFixed(1); const ratioVal = (+data / (maxValue - minValue)).toFixed(1); const isWarn = +data >= warnValue; const isSerious = +data >= seriousValue; const totalColor = Waves.map(i => { if (isSerious) { return "#FF0000" } else if (isWarn){ return "#F8E71C" } else { return i.color; } }); const totalDatas = totalColor.map(() => { return { name: '温度', //数据项名称
value: +ratioVal, rawValue: +data } }) console.log('totalDatas', totalDatas); var unit = '℃'; var svgPath = 'path://M570,729.5V86.4c0-42.2-31.4-76.4-70-76.4s-70,34.2-70,76.4v643c-41.7,24.3-70,68.9-70,120.6c0,77.3,62.7,140,140,140s140-62.7,140-140C640,798.3,611.7,753.7,570,729.5z';//温度计SVG路径
var option = { backgroundColor: '', //背景颜色
title: { //标题样式
text: title.text, //主标题
subtext: \`\${temperature}\${unit}\`, //副标题
textStyle: { //标题的样式
color: title.textStyle.color, fontFamily: 'Microsoft YaHei', align: 'center', verticalAlign: 'middle', fontSize: title.textStyle.fontSize }, subtextStyle: { //副标题的样式
color: title.subtextStyle.color, fontSize: title.subtextStyle.fontSize }, top: '45%', left: '50%', itemGap: 10,//主副标题之间的间距。
backgroundColor: 'transparent' //标题背景色,默认透明,设置无效
}, tooltip: { //提示框浮层属性
show: true, //默认为true
transitionDuration: 0.8, //提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动
formatter: function (item) { //提示框浮层内容格式器,支持字符串模板和回调函数两种形式
return \`\${temperature}\${unit}\`;
} }, series: [{ name: '温度', //系列名称
type: 'liquidFill', //系列类型
shape: svgPath, //水填充图的形状 circle默认圆形 rect圆角矩形 triangle三角形 diamond菱形 pin水滴状 arrow箭头状 还可以是svg的path
center: ['30%', '50%'], //图表相对于盒子的位置[水平, 垂直],默认是[50%,50%]在水平、垂直方向居中 可设置百分比活着具体数值
radius: '90%', //图表的大小 值是圆的直径 可以是百分比 也可以是具体值 100%则占满整个盒子 默认是40% 百分比下是根据宽高最小的一个为参照依据
amplitude: 3, //振幅 是波浪的震荡幅度 可以取具体的值 也可以是百分比 百分比下是按图标的直径来算
waveLength: '42%', //波的长度 可以是百分比也可以是具体的像素值 百分比下是相对于直径的 取得越大波浪的起伏越小
phase: 0, //波的相位弧度 默认情况下是自动
direction: 'left', //波移动的速度 两个参数 left 从右往左 right 从左往右
waveAnimation: true, //控制波动画的开关,布尔值: false关闭动画,true开启动画(默认值)
animationEasing: 'linear', //初始动画
animationEasingUpdate: 'quarticInOut', //数据更新的动画效果
animationDuration: 1500, //初始动画的时长,支持回调函数,可以通过每个数据返回不同的 delay 时间实现更绚丽的初始动画效果
animationDurationUpdate: 200, //数据更新动画的时长
data: totalDatas, label: { //图表内部字体
normal: { formatter: '' } }, outline: outline, backgroundStyle, color: totalColor, itemStyle: { opacity: 0.8, //波浪的透明度
shadowBlur: 10, //波浪的阴影范围
shadowColor: '#ecfc03' //阴影颜色
}, emphasis: { itemStyle: { opacity: 1 //鼠标经过波浪颜色的透明度
} } }] };
// console.log('option', option);
const func = new Function('option', 'datas', codeConfig); const opt = func(window._.cloneDeep(option), data);
// console.log('opt', opt);
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(opt); } } }
watch([currentData, chartProps], ([val, pros]) => { nextTick(() => { initChart(val, pros) }) }, { immediate: true, deep: true, }) }}
class CustomThermWaterFillNode extends HtmlResize.view { realValue = defaultVal oldProperties = {} chartRendered = false instance = null
setHtml(rootEl) { if (!rootEl) return; const { properties, width, height } = this.props.model; const { normalData } = properties.dynamic || {} let thingName = 'pressure'; let attr = 'score'; if (normalData && normalData.dataPoint) { const dataPointStrParsed = JSON.parse(normalData.dataPoint || '{}') const { deviceCode, dataPoint } = dataPointStrParsed; thingName = deviceCode; attr = dataPoint.split(',')[0]; } if (this.instance) { // 实时数据不能推送一次就创建一次图表,可以在原有实例基础之上更改数据。
Object.assign(this.instance.component.props, { name: properties.nodeAlias, chartId: \`waterfill-\${properties.id}\`,
currentData: this.realValue, width, height, chartProps: properties, thingName, attr, unit: normalData.unit || 'km/h' }) return } const el = document.createElement('div'); rootEl.innerHTML = ''; const instance = createVNode(ThermWaterFill, { name: properties.nodeAlias, chartId: \`gauge-\${properties.id}\`,
currentData: this.realValue, width, height, chartProps: properties, thingName, attr, unit: normalData.unit || 'km/h' }) instance.appContext = app._context render(instance, el) rootEl.appendChild(el); this.instance = instance; }
sameProps(properties) { const isSame = window._.isEqual(this.oldProperties, properties); if (isSame) return true; this.oldProperties = properties; return false }
// 生命周期 支持重写内容, 但格式需一致
shouldUpdate() { const { properties } = this.props.model; const { normalData } = properties.dynamic || {};
if (normalData && !normalData.dataPoint && !normalData.defaultValue) { this.realValue = defaultVal; return true }
if (normalData) { const { defaultValue } = normalData || {}; if (defaultValue) { const realValue = window.resolveScadaNewValue(defaultValue) if (this.realValue !== Number(realValue)) { this.realValue = Number(realValue); return true; } } }
const propertiesBack = window._.cloneDeep(properties); if (propertiesBack.dynamic.normalData) { const isSameProps = this.sameProps(propertiesBack); if (isSameProps && this.chartRendered) { return false } else { if (!this.chartRendered) { this.chartRendered = true return true } if (!isSameProps) { return true; } } } }
updateHtml() { this.setHtml(this.rootEl); }
componentDidMount() { // 防止拖动时候频繁渲染图表
this.updateHtmlDebounced = window._.debounce(this.updateHtml.bind(this), 500); if (this.shouldUpdate()) { this.setHtml(this.rootEl); } }
componentDidUpdate() { if (this.shouldUpdate()) { this.updateHtmlDebounced(); } }}
class CustomThermWaterFillModel 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-therm-waterfill-node', view: CustomThermWaterFillNode, model: CustomThermWaterFillModel,})`,css:"",fakeData:""},v={id:t,name:e,aliasName:a,image:n,imageType:f,groupName:l,groupType:o,isRemote:!1,isDefault:!0,sectionType:r,config:s,files:d};export{a as aliasName,s as config,v as default,d as files,l as groupName,o as groupType,t as id,n as image,f as imageType,A as isDefault,i as isRemote,e as name,r as sectionType};
|