Showing
5 changed files
with
832 additions
and
101 deletions
... | ... | @@ -272,8 +272,12 @@ |
272 | 272 | /** |
273 | 273 | * @description 图片组件 |
274 | 274 | */ |
275 | - IMAGE: 'image' | |
276 | - | |
275 | + IMAGE: 'image', | |
276 | + | |
277 | + /** | |
278 | + * @description 流量计 | |
279 | + */ | |
280 | + FLOWMETER: 'flowmeter' | |
277 | 281 | } |
278 | 282 | |
279 | 283 | Sidebar.prototype.enumComponentTypeValue = { |
... | ... | @@ -364,7 +368,12 @@ |
364 | 368 | /** |
365 | 369 | * @description 运行于停止 |
366 | 370 | */ |
367 | - RUNNING_AND_STOP: 'runningAndStop' | |
371 | + RUNNING_AND_STOP: 'runningAndStop', | |
372 | + | |
373 | + /** | |
374 | + * @description 流量计 | |
375 | + */ | |
376 | + FLOWMETER_PANEL: 'flowmeter' | |
368 | 377 | } |
369 | 378 | |
370 | 379 | /** |
... | ... | @@ -721,8 +730,8 @@ |
721 | 730 | //更多图形,显示出来的的标题跟id,同时包括图片 |
722 | 731 | |
723 | 732 | // TODO thingsKit 设置数据绑定展示面板 |
724 | - const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DASHBOARD_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION, VIDEO: VIDEO_PANEL, SWITCH_STATE_SETTING, ONLY_SINGLE_EVENT, RUNNING_AND_STOP } = this.enumPermissionPanel | |
725 | - const { LINE, LINE_CHART, REAL_TIME, TITLE, VARIABLE, DEFAULT, BAR_CHART, VIDEO, SWITCH, PARAMS_SETTING_BUTTON, DASHBOARD_CHART, IMAGE } = this.enumComponentType | |
733 | + const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DASHBOARD_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION, VIDEO: VIDEO_PANEL, SWITCH_STATE_SETTING, ONLY_SINGLE_EVENT, RUNNING_AND_STOP, FLOWMETER_PANEL } = this.enumPermissionPanel | |
734 | + const { LINE, LINE_CHART, REAL_TIME, TITLE, VARIABLE, DEFAULT, BAR_CHART, VIDEO, SWITCH, PARAMS_SETTING_BUTTON, DASHBOARD_CHART, IMAGE, FLOWMETER } = this.enumComponentType | |
726 | 735 | this.setComponentPermission(LINE, [RUNNING_AND_STOP, DYNAMIC_EFFECT]) |
727 | 736 | this.setComponentPermission(DEFAULT, [DYNAMIC_EFFECT]) |
728 | 737 | this.setComponentPermission(REAL_TIME, [DYNAMIC_EFFECT]) |
... | ... | @@ -736,6 +745,7 @@ |
736 | 745 | this.setComponentPermission(SWITCH, [DATA_SOURCE, SWITCH_STATE_SETTING]) |
737 | 746 | this.setComponentPermission(PARAMS_SETTING_BUTTON, [DATA_SOURCE, ONLY_SINGLE_EVENT]) |
738 | 747 | this.setComponentPermission(IMAGE, [DATA_SOURCE]) |
748 | + this.setComponentPermission(FLOWMETER, [DATA_SOURCE, FLOWMETER_PANEL]) | |
739 | 749 | |
740 | 750 | var thingskitEntries = [ |
741 | 751 | { title: mxResources.get('general'), id: 'general', image: IMAGE_PATH + '/sidebar-general.png' }, | ... | ... |
... | ... | @@ -42,10 +42,29 @@ |
42 | 42 | CHART_IMG_PLACEHOLDER_SIZE: 30, |
43 | 43 | } |
44 | 44 | |
45 | + Sidebar.prototype.enumFlowmeterAttr = { | |
46 | + WIDTH: 'width', | |
47 | + HEIGHT: 'height', | |
48 | + VALUE: 'value', | |
49 | + TYPE: 'type', | |
50 | + UUID: 'uuid', | |
51 | + BG_COLOR: 'bgColor', | |
52 | + WAVE_FIRST_COLOR: 'waveFirstColor', | |
53 | + WAVE_SECOND_COLOR: 'waveSecondColor', | |
54 | + WAVE_THIRD_COLOR: 'waveThirdColor', | |
55 | + } | |
56 | + | |
57 | + Sidebar.prototype.enumFlowmeterType = { | |
58 | + RECT: 'rect', | |
59 | + CIRCLE: 'circle', | |
60 | + THERMOMETER: 'thermometer' | |
61 | + } | |
62 | + | |
45 | 63 | // Adds Atlassian shapes |
46 | 64 | // 图表 |
47 | 65 | Sidebar.prototype.addChartsPalette = function () { |
48 | 66 | this.chartsComponentInit() |
67 | + | |
49 | 68 | const self = this |
50 | 69 | const componentType = this.enumComponentType |
51 | 70 | const { DATA_SOURCE, DYNAMIC_EFFECT, DISPLAY_TYPE } = this.enumPermissionPanel |
... | ... | @@ -74,7 +93,19 @@ |
74 | 93 | const id = self.generatorChartsId() |
75 | 94 | const cell = self.generatorCell(id, enumConst.CHART_IMG_PLACEHOLDER_SIZE, enumConst.CHART_IMG_PLACEHOLDER_SIZE, componentType.DASHBOARD_CHART, `${Proxy_Prefix}/images/thingskit/dashboard-chart.png`) |
76 | 95 | return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '仪表盘'); |
77 | - })) | |
96 | + })), | |
97 | + this.addEntry('flowmeter-circle', mxUtils.bind(this, function () { | |
98 | + const cell = self.generateFlowmeterCell(100, 100, Sidebar.prototype.enumFlowmeterType.CIRCLE) | |
99 | + return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '流量计'); | |
100 | + })), | |
101 | + this.addEntry('flowmeter-rect', mxUtils.bind(this, function () { | |
102 | + const cell = self.generateFlowmeterCell(100, 100, Sidebar.prototype.enumFlowmeterType.RECT) | |
103 | + return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '流量计'); | |
104 | + })), | |
105 | + this.addEntry('flowmeter-thermometer', mxUtils.bind(this, function () { | |
106 | + const cell = self.generateFlowmeterCell(100, 100, Sidebar.prototype.enumFlowmeterType.THERMOMETER) | |
107 | + return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '流量计'); | |
108 | + })), | |
78 | 109 | ]; |
79 | 110 | |
80 | 111 | this.addPaletteFunctions('charts', '图表', false, fns); |
... | ... | @@ -210,7 +241,8 @@ |
210 | 241 | Sidebar.prototype.addClickHandler = function (elt, ds, cells) { |
211 | 242 | const cell = cells[0] |
212 | 243 | const cellValue = cell.value |
213 | - const validate = cellValue && cellValue.nodeName === 'UserObject' && this.isChartCell(cell) | |
244 | + const validateChart = cellValue && cellValue.nodeName === 'UserObject' && this.isChartCell(cell) | |
245 | + const validateFlowmeter = cellValue && cellValue.nodeName === 'UserObject' && this.isFlowmeter(cell) | |
214 | 246 | |
215 | 247 | /** |
216 | 248 | * @description 拓展Sidebar鼠标按下 |
... | ... | @@ -218,7 +250,7 @@ |
218 | 250 | */ |
219 | 251 | const mouseDown = ds.mouseDown |
220 | 252 | ds.mouseDown = function (evt) { |
221 | - if (validate) { | |
253 | + if (validateChart) { | |
222 | 254 | const id = self.generatorChartsId() |
223 | 255 | const geo = Object.assign(graph.model.getGeometry(cell), { width: 400, height: 400 }) |
224 | 256 | cell.setGeometry(geo) |
... | ... | @@ -227,6 +259,14 @@ |
227 | 259 | self.graph.setAttributeForCell(cell, enumConst.CHART_CELL_HEIGHT, enumConst.CHART_CELL_DEFAULT_HEIGHT); |
228 | 260 | self.graph.setAttributeForCell(cell, 'label', self.createChartsNode(id)) |
229 | 261 | } |
262 | + | |
263 | + if (validateFlowmeter) { | |
264 | + const { UUID, TYPE } = getFlowmeterAttrKey() | |
265 | + const id = uuid() | |
266 | + const type = self.graph.getAttributeForCell(cell, TYPE) | |
267 | + self.graph.setAttributeForCell(cell, UUID, id); | |
268 | + self.graph.setAttributeForCell(cell, 'label', Sidebar.prototype.generateFlowmeterTemplate(id, type)); | |
269 | + } | |
230 | 270 | mouseDown.apply(this, arguments) |
231 | 271 | }; |
232 | 272 | |
... | ... | @@ -239,7 +279,7 @@ |
239 | 279 | try { |
240 | 280 | mouseUp.apply(this, arguments) |
241 | 281 | } finally { |
242 | - if (validate) { | |
282 | + if (validateChart) { | |
243 | 283 | const id = self.getCellId(cell) |
244 | 284 | const chartType = cell.getAttribute(basicAttr.COMPONENT_TYPE) |
245 | 285 | self.generatorEChartInstance(id, enumConst.CHART_CELL_DEFAULT_WIDTH, enumConst.CHART_CELL_DEFAULT_HEIGHT, chartType) |
... | ... | @@ -332,6 +372,7 @@ |
332 | 372 | const { width, height, chartType } = domIdMapping.get(id) |
333 | 373 | Sidebar.prototype.generatorEChartInstance(id, width, height, chartType) |
334 | 374 | } |
375 | + // Sidebar.prototype.initFlowmeter(graph) | |
335 | 376 | } |
336 | 377 | |
337 | 378 | /** |
... | ... | @@ -357,6 +398,7 @@ |
357 | 398 | refresh.apply(this, arguments) |
358 | 399 | if (!arguments.length) { |
359 | 400 | Sidebar.prototype.initChartInstance(this) |
401 | + Sidebar.prototype.resetFlowmeter(this) | |
360 | 402 | } |
361 | 403 | } |
362 | 404 | |
... | ... | @@ -367,6 +409,7 @@ |
367 | 409 | EditorUi.prototype.setFileData = function () { |
368 | 410 | setFileData.apply(this, arguments) |
369 | 411 | Sidebar.prototype.initChartInstance(this.editor.graph) |
412 | + Sidebar.prototype.resetFlowmeter(this.editor.graph) | |
370 | 413 | } |
371 | 414 | |
372 | 415 | // const selectPage = EditorUi.prototype.selectPage |
... | ... | @@ -496,5 +539,419 @@ |
496 | 539 | } |
497 | 540 | } |
498 | 541 | |
542 | + function uuid() { | |
543 | + return Number(Math.random().toString().substring(2)).toString(32) | |
544 | + } | |
545 | + | |
546 | + /** | |
547 | + * @description 生成流量计模版 | |
548 | + */ | |
549 | + Sidebar.prototype.generateFlowmeterTemplate = function (id = uuid(), type) { | |
550 | + const flowmeterType = Sidebar.prototype.enumFlowmeterType | |
551 | + const typeGenFn = { | |
552 | + [flowmeterType.CIRCLE]: Sidebar.prototype.generateFlowmeterCircle, | |
553 | + [flowmeterType.RECT]: Sidebar.prototype.generateFlowmeterRect, | |
554 | + [flowmeterType.THERMOMETER]: Sidebar.prototype.generateFlowmeterThermometer, | |
555 | + } | |
556 | + const template = `<div class="flowmeter" style="transform: scale(0.9);font-size: 0;" id="${id}">${typeGenFn[type] && typeGenFn[type]()}</div>` | |
557 | + return template | |
558 | + } | |
559 | + | |
560 | + Sidebar.prototype.generateFlowmeterCell = function (width = 100, height = 100, type) { | |
561 | + const id = uuid() | |
562 | + const template = Sidebar.prototype.generateFlowmeterTemplate(id, type) | |
563 | + const cell = new mxCell(template, new mxGeometry(0, 0, width, height), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;'); | |
564 | + cell.setVertex(true) | |
565 | + const componentType = Sidebar.prototype.enumComponentType | |
566 | + const { WIDTH, HEIGHT, VALUE, TYPE, COMPONENT_TYPE, UUID } = getFlowmeterAttrKey() | |
567 | + this.graph.setAttributeForCell(cell, WIDTH, width); | |
568 | + this.graph.setAttributeForCell(cell, HEIGHT, height); | |
569 | + this.graph.setAttributeForCell(cell, VALUE, 20); | |
570 | + this.graph.setAttributeForCell(cell, TYPE, type); | |
571 | + this.graph.setAttributeForCell(cell, UUID, id); | |
572 | + this.graph.setAttributeForCell(cell, COMPONENT_TYPE, componentType.FLOWMETER); | |
573 | + return cell | |
574 | + } | |
575 | + | |
576 | + Sidebar.prototype.generateFlowmeterRect = function () { | |
577 | + return ` | |
578 | + <svg class="waves-rect" viewBox="0 0 100 100" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" | |
579 | + xmlns:xlink="http://www.w3.org/1999/xlink" | |
580 | + style="--width: 100; --height: 100; --value: 20; --play-state: running; --full-flag: clamp(0, calc(100 - var(--value)), 1); --over-min-flag: clamp(0, calc(calc(var(--value) - 1) * -1), 1);"> | |
581 | + <defs> | |
582 | + <style> | |
583 | + .waves-rect { | |
584 | + width: calc(var(--width) * 1px); | |
585 | + height: calc(var(--height) * 1px); | |
586 | + } | |
587 | + | |
588 | + @keyframes move { | |
589 | + from { | |
590 | + transform: translate(-90px, 0%); | |
591 | + } | |
592 | + | |
593 | + to { | |
594 | + transform: translate(85px, 0%); | |
595 | + } | |
596 | + } | |
597 | + | |
598 | + .wave { | |
599 | + animation: move 3s linear infinite; | |
600 | + animation-play-state: running; | |
601 | + } | |
602 | + | |
603 | + .wave:nth-child(1) { | |
604 | + animation-delay: -2s; | |
605 | + animation-duration: 9s; | |
606 | + } | |
607 | + | |
608 | + .wave:nth-child(2) { | |
609 | + animation-delay: -4s; | |
610 | + animation-duration: 6s; | |
611 | + } | |
612 | + | |
613 | + .wave:nth-child(3) { | |
614 | + animation-delay: -6s; | |
615 | + animation-duration: 3s; | |
616 | + } | |
617 | + | |
618 | + .waves-rect>g+rect { | |
619 | + transform: translateY(calc(calc(100 - var(--value)) * var(--full-flag) * 1% + var(--full-flag) * 15%)); | |
620 | + transition: transform linear 1s; | |
621 | + } | |
622 | + | |
623 | + .height { | |
624 | + transform: translateY(calc(var(--value) * -1% - 10% + var(--over-min-flag) * 10%)); | |
625 | + transition: transform linear 1s; | |
626 | + } | |
627 | + | |
628 | + .waves-rect .text { | |
629 | + display: flex; | |
630 | + justify-content: center; | |
631 | + align-items: center; | |
632 | + width: 100%; | |
633 | + height: 100%; | |
634 | + color: #fff; | |
635 | + font-size: 18px; | |
636 | + font-weight: 700; | |
637 | + } | |
638 | + | |
639 | + .waves-rect .text::after { | |
640 | + counter-reset: value var(--value); | |
641 | + content: counter(value) ' %'; | |
642 | + } | |
643 | + </style> | |
644 | + <path id="wave" d="M-160 118c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v100h-352z" /> | |
645 | + </defs> | |
646 | + <rect class="bgColor" x="0" y="0" width="100" height="100" fill="#8badcb"></rect> | |
647 | + <g class="height"> | |
648 | + <use class="wave waveFirst" xlink:href="#wave" fill="#4579e2" x="0" y="0"></use> | |
649 | + <use class="wave waveSecond" xlink:href="#wave" fill="#3461c1" x="0" y="2"></use> | |
650 | + <use class="wave waveThird" xlink:href="#wave" fill="#2d55aa" x="0" y="4"></use> | |
651 | + </g> | |
652 | + <rect class="waveThird" x="0" y="0" width="100" height="100" fill="#2d55aa"></rect> | |
653 | + <foreignObject x="0" y="0" width="100" height="100" text-anchor="middle" dominant-baseline="middle"> | |
654 | + <div xmlns="http://www.w3.org/1999/xhtml" class="text"></div> | |
655 | + </foreignObject> | |
656 | +</svg> | |
657 | + `.replace(/\n/g, '') | |
658 | + } | |
659 | + | |
660 | + Sidebar.prototype.generateFlowmeterCircle = function () { | |
661 | + return ` | |
662 | + <svg class="waves-circle" viewBox="0 0 100 100" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" | |
663 | + xmlns:xlink="http://www.w3.org/1999/xlink" | |
664 | + style="--width: 100; --height: 100; --value: 20; --play-state: running; --full-flag: clamp(0, calc(100 - var(--value)), 1); --over-min-flag: clamp(0, calc(calc(var(--value) - 1) * -1), 1)"> | |
665 | + <style> | |
666 | + .waves-circle { | |
667 | + width: calc(min(var(--width), var(--height)) * 1px); | |
668 | + height: calc(min(var(--width), var(--height)) * 1px); | |
669 | + clip-path: circle(calc(min(var(--width), var(--height)) / 2 * 1px)); | |
670 | + } | |
671 | + | |
672 | + @keyframes move { | |
673 | + from { | |
674 | + transform: translate(-90px, 0%); | |
675 | + } | |
676 | + | |
677 | + to { | |
678 | + transform: translate(85px, 0%); | |
679 | + } | |
680 | + } | |
681 | + | |
682 | + .wave { | |
683 | + animation: move 3s linear infinite; | |
684 | + animation-play-state: var(--play-state); | |
685 | + } | |
686 | + | |
687 | + .wave:nth-child(1) { | |
688 | + animation-delay: -2s; | |
689 | + animation-duration: 9s; | |
690 | + } | |
691 | + | |
692 | + .wave:nth-child(2) { | |
693 | + animation-delay: -4s; | |
694 | + animation-duration: 6s; | |
695 | + } | |
696 | + | |
697 | + .wave:nth-child(3) { | |
698 | + animation-delay: -6s; | |
699 | + animation-duration: 3s; | |
700 | + } | |
701 | + | |
702 | + .height { | |
703 | + transform: translateY(calc(var(--value) * -1% - 10% + var(--over-min-flag) * 10%)); | |
704 | + transition: transform linear 1s; | |
705 | + } | |
706 | + | |
707 | + .waves-circle>g+rect { | |
708 | + transform: translateY(calc(calc(100 - var(--value)) * var(--full-flag) * 1% + var(--full-flag) * 15%)); | |
709 | + transition: transform linear 1s; | |
710 | + } | |
711 | + | |
712 | + .waves-circle .text { | |
713 | + display: flex; | |
714 | + justify-content: center; | |
715 | + align-items: center; | |
716 | + width: 100%; | |
717 | + height: 100%; | |
718 | + color: #fff; | |
719 | + font-size: 18px; | |
720 | + font-weight: 700; | |
721 | + } | |
722 | + | |
723 | + .waves-circle .text::after { | |
724 | + counter-reset: value var(--value); | |
725 | + content: counter(value) ' %'; | |
726 | + } | |
727 | + </style> | |
728 | + <defs> | |
729 | + <path id="wave" d="M-160 118c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v100h-352z" /> | |
730 | + </defs> | |
731 | + <circle class="bgColor" cx="50" cy="50" r="50" fill="#8badcb" /> | |
732 | + <g class="height"> | |
733 | + <use class="wave waveFirst" xlink:href="#wave" fill="#4579e2" x="0" y="0"></use> | |
734 | + <use class="wave waveSecond" xlink:href="#wave" fill="#3461c1" x="0" y="2"></use> | |
735 | + <use class="wave waveThird" xlink:href="#wave" fill="#2d55aa" x="0" y="4"></use> | |
736 | + </g> | |
737 | + <rect class="waveThird" x="0" y="0" width="100" height="100" fill="#2d55aa"></rect> | |
738 | + <foreignObject x="0" y="0" width="100" height="100" text-anchor="middle" dominant-baseline="middle"> | |
739 | + <div xmlns="http://www.w3.org/1999/xhtml" class="text"></div> | |
740 | + </foreignObject> | |
741 | + </svg> | |
742 | + `.replace(/\n/g, '') | |
743 | + } | |
744 | + | |
745 | + Sidebar.prototype.generateFlowmeterThermometer = function () { | |
746 | + return ` | |
747 | + <svg class="flowmeter-thermometer" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg" | |
748 | + style="--range: 4; --min: 50; --max: 70; --width: 100; --height: 100; --value: 50;"> | |
749 | + <style> | |
750 | + .flowmeter-thermometer { | |
751 | + width: calc(min(var(--width), var(--height)) * 1px); | |
752 | + height: calc(min(var(--width), var(--height)) * 1px); | |
753 | + } | |
754 | + | |
755 | + .thermometer-mercury-column { | |
756 | + y: var(--value); | |
757 | + } | |
758 | + | |
759 | + .tick-label { | |
760 | + font-size: 12px; | |
761 | + text-align: right; | |
762 | + overflow: hidden; | |
763 | + text-overflow: ellipsis; | |
764 | + color: #5b6b73; | |
765 | + } | |
766 | + | |
767 | + .thermometer-mercury-column { | |
768 | + transition: y .5s cubic-bezier(0.52, 0.05, 0.47, 0.99); | |
769 | + } | |
770 | + </style> | |
771 | + <defs> | |
772 | + <radialGradient id="thermometerdiv_meter_2" cx="50%" cy="50%" r="50%" fx="50%" fy="50%"> | |
773 | + <stop offset="0%" style="stop-color: rgb(230, 200, 200);"></stop> | |
774 | + <stop offset="90%" style="stop-color: rgb(230, 0, 0);"></stop> | |
775 | + </radialGradient> | |
776 | + <clipPath id="over"> | |
777 | + <rect width="100" height="190" x="100" y="10" /> | |
778 | + </clipPath> | |
779 | + </defs> | |
780 | + <circle r="9.25" cx="109" cy="14.25" style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136); stroke-width: 1px;"> | |
781 | + </circle> | |
782 | + <rect x="99.75" y="14.25" height="192.75" width="18.5" | |
783 | + style="shape-rendering: crispedges; fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136); stroke-width: 1px;"> | |
784 | + </rect> | |
785 | + <circle r="8.75" cx="109" cy="14.25" style="fill: rgb(255, 255, 255); stroke: none;"></circle> | |
786 | + <circle r="18" cx="109" cy="207" style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136);"></circle> | |
787 | + <rect x="100.25" y="14.25" height="192.75" width="17.5" | |
788 | + style="shape-rendering: crispedges; fill: rgb(255, 255, 255); stroke: none;"></rect> | |
789 | + <line class="thermometer-min-line" x1="99.75" x2="140.25" y1="165" y2="165" | |
790 | + style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispedges;"></line> | |
791 | + <text class="thermometer-min-label" x="120.25" y="168.46428571428572" dy="0.72em" | |
792 | + style="fill: rgb(0, 0, 230); font-size: 10px;">min</text> | |
793 | + <line class="thermometer-max-line" x1="99.75" x2="140.25" y1="40" y2="40" | |
794 | + style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispedges;"></line> | |
795 | + <text class="thermometer-max-label" x="120.25" y="35.285714285714306" | |
796 | + style="fill: rgb(230, 0, 0); font-size: 10px;">max</text> | |
797 | + <rect class="thermometer-mercury-column" x="104" y="15" width="10.5" height="190" | |
798 | + style="shape-rendering: crispedges; fill: rgb(230, 0, 0);" clip-path="url(#over)"></rect> | |
799 | + <circle r="13" cx="109" cy="207" | |
800 | + style="fill: url("#thermometerdiv_meter_2"); stroke: rgb(230, 0, 0); stroke-width: 2px;"></circle> | |
801 | + <g class="thermometer-temperature-axis" transform="translate(99.75,0)" fill="none" font-size="10" | |
802 | + font-family="sans-serif" text-anchor="end"> | |
803 | + <g class="tick" opacity="1" transform="translate(0,190)"> | |
804 | + <line stroke="currentColor" x2="-7" | |
805 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
806 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
807 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">-20</div> | |
808 | + </foreignObject> | |
809 | + </g> | |
810 | + <g class="tick" opacity="1" transform="translate(0,165)"> | |
811 | + <line stroke="currentColor" x2="-7" | |
812 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
813 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
814 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">0</div> | |
815 | + </foreignObject> | |
816 | + </g> | |
817 | + <g class="tick" opacity="1" transform="translate(0,140)"> | |
818 | + <line stroke="currentColor" x2="-7" | |
819 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
820 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
821 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">20</div> | |
822 | + </foreignObject> | |
823 | + </g> | |
824 | + <g class="tick" opacity="1" transform="translate(0,115)"> | |
825 | + <line stroke="currentColor" x2="-7" | |
826 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
827 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
828 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">40</div> | |
829 | + </foreignObject> | |
830 | + </g> | |
831 | + <g class="tick" opacity="1" transform="translate(0,90)"> | |
832 | + <line stroke="currentColor" x2="-7" | |
833 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
834 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
835 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">60</div> | |
836 | + </foreignObject> | |
837 | + </g> | |
838 | + <g class="tick" opacity="1" transform="translate(0,65)"> | |
839 | + <line stroke="currentColor" x2="-7" | |
840 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
841 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
842 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">80</div> | |
843 | + </foreignObject> | |
844 | + </g> | |
845 | + <g class="tick" opacity="1" transform="translate(0,40)"> | |
846 | + <line stroke="currentColor" x2="-7" | |
847 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
848 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
849 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">100</div> | |
850 | + </foreignObject> | |
851 | + </g> | |
852 | + <g class="tick" opacity="1" transform="translate(0,15)"> | |
853 | + <line stroke="currentColor" x2="-7" | |
854 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
855 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
856 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">120</div> | |
857 | + </foreignObject> | |
858 | + </g> | |
859 | + </g> | |
860 | + </svg> | |
861 | + `.replace(/\n/g, '') | |
862 | + } | |
863 | + | |
864 | + Sidebar.prototype.resetFlowmeter = function (graph) { | |
865 | + const { COMPONENT_TYPE, UUID, WIDTH, HEIGHT } = getFlowmeterAttrKey() | |
866 | + const componentType = Sidebar.prototype.enumComponentType | |
867 | + const cells = Object.entries(graph?.getModel()?.cells || {}).map(([_, item]) => item) || [] | |
868 | + const needReset = cells.filter(item => item.value && item.getAttribute(COMPONENT_TYPE) === componentType.FLOWMETER) | |
869 | + | |
870 | + needReset.forEach(item => { | |
871 | + const id = item.getAttribute(UUID) | |
872 | + const element = document.getElementById(id).querySelector('svg') | |
873 | + if (element) { | |
874 | + const width = item.getAttribute(WIDTH) | |
875 | + const height = item.getAttribute(HEIGHT) | |
876 | + | |
877 | + element.style.setProperty('--width', width) | |
878 | + element.style.setProperty('--height', height) | |
879 | + } | |
880 | + }) | |
881 | + } | |
882 | + | |
883 | + Sidebar.prototype.isFlowmeter = function (cell) { | |
884 | + const basicAttr = Sidebar.prototype.enumCellBasicAttribute | |
885 | + const componentType = Sidebar.prototype.enumComponentType | |
886 | + return cell.getAttribute(basicAttr.COMPONENT_TYPE) === componentType.FLOWMETER | |
887 | + } | |
888 | + | |
889 | + Sidebar.prototype.updateFlowmeterCell = function (cell, { width, height, value, type }) { | |
890 | + const { WIDTH, HEIGHT, VALUE, TYPE, UUID } = getFlowmeterAttrKey() | |
891 | + const id = cell.getAttribute(UUID) | |
892 | + const element = document.getElementById(id).querySelector('svg') | |
893 | + if (element) { | |
894 | + width && element.style.setProperty('--width', width) | |
895 | + height && element.style.setProperty('--height', height) | |
896 | + value && element.style.setProperty('--value', value) | |
897 | + width && cell.setAttribute(WIDTH, width) | |
898 | + height && cell.setAttribute(HEIGHT, height) | |
899 | + value && cell.setAttribute(VALUE, value) | |
900 | + type && cell.setAttribute(TYPE, type) | |
901 | + } | |
902 | + } | |
903 | + | |
904 | + /** | |
905 | + * @description charts cell发生resize时改变charts size | |
906 | + * @type {Function} | |
907 | + */ | |
908 | + const cellResized = mxGraph.prototype.cellResized | |
909 | + mxGraph.prototype.cellResized = function (cell, rect) { | |
910 | + | |
911 | + if (Sidebar.prototype.isFlowmeter(cell)) { | |
912 | + const { width, height } = rect | |
913 | + Sidebar.prototype.updateFlowmeterCell(cell, { width, height }) | |
914 | + } | |
915 | + cellResized.apply(this, arguments) | |
916 | + } | |
499 | 917 | })(); |
500 | 918 | |
919 | +/** | |
920 | + * @description 获取流量计属性key | |
921 | + * @returns {{WIDTH: 'width', HEIGHT: 'height', VALUE: 'value', TYPE: 'type', UUID: 'uuid', COMPONENT_TYPE: 'componentType', BG_COLOR: 'bgColor', WAVE_FIRST_COLOR: 'waveFirstColor', WAVE_SECOND_COLOR: 'waveSecondColor', WAVE_THIRD_COLOR: 'waveThirdColor'}} | |
922 | + */ | |
923 | +function getFlowmeterAttrKey() { | |
924 | + const basicAttr = Sidebar.prototype.enumCellBasicAttribute | |
925 | + const flowmeterAttr = Sidebar.prototype.enumFlowmeterAttr | |
926 | + return { | |
927 | + WIDTH: flowmeterAttr.WIDTH, | |
928 | + HEIGHT: flowmeterAttr.HEIGHT, | |
929 | + VALUE: flowmeterAttr.VALUE, | |
930 | + TYPE: flowmeterAttr.TYPE, | |
931 | + UUID: flowmeterAttr.UUID, | |
932 | + BG_COLOR: flowmeterAttr.BG_COLOR, | |
933 | + WAVE_FIRST_COLOR: flowmeterAttr.WAVE_FIRST_COLOR, | |
934 | + WAVE_SECOND_COLOR: flowmeterAttr.WAVE_SECOND_COLOR, | |
935 | + WAVE_THIRD_COLOR: flowmeterAttr.WAVE_THIRD_COLOR, | |
936 | + UUID: flowmeterAttr.UUID, | |
937 | + COMPONENT_TYPE: basicAttr.COMPONENT_TYPE, | |
938 | + } | |
939 | +} | |
940 | + | |
941 | +/** | |
942 | + * @description 获取流量计类型 | |
943 | + * @returns {{RECT: 'rect', CIRCLE: 'circle'}} | |
944 | + */ | |
945 | +function getFlowmeterType() { | |
946 | + const type = Sidebar.prototype.enumFlowmeterType | |
947 | + return { | |
948 | + RECT: type.RECT, | |
949 | + CIRCLE: type.CIRCLE | |
950 | + } | |
951 | +} | |
952 | + | |
953 | + | |
954 | +function getComponentType() { | |
955 | + const componentType = Sidebar.prototype.enumComponentType | |
956 | + return | |
957 | +} | ... | ... |
... | ... | @@ -5132,7 +5132,8 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
5132 | 5132 | [permissionKey.VIDEO]: createVideoBindPanel, |
5133 | 5133 | [permissionKey.SWITCH_STATE_SETTING]: createSwitchStateSettingPanel, |
5134 | 5134 | [permissionKey.ONLY_SINGLE_EVENT]: createParamsSettingButtonPanel, |
5135 | - [permissionKey.RUNNING_AND_STOP]: createRunningAndStopPanel | |
5135 | + [permissionKey.RUNNING_AND_STOP]: createRunningAndStopPanel, | |
5136 | + [permissionKey.FLOWMETER_PANEL]: createFlowmeterPanel | |
5136 | 5137 | } |
5137 | 5138 | |
5138 | 5139 | |
... | ... | @@ -5241,6 +5242,7 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
5241 | 5242 | * @type {Function} |
5242 | 5243 | */ |
5243 | 5244 | const refreshFn = echoRefreshFn |
5245 | + | |
5244 | 5246 | echoRefreshFn = function () { |
5245 | 5247 | refreshFn.apply(this) |
5246 | 5248 | const { dataSources: [dataSource] = [] } = currentNodeData || {} |
... | ... | @@ -5428,6 +5430,70 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
5428 | 5430 | } |
5429 | 5431 | |
5430 | 5432 | /** |
5433 | + * @description 创建流量计面板 | |
5434 | + */ | |
5435 | + function createFlowmeterPanel() { | |
5436 | + | |
5437 | + const enumConst = { | |
5438 | + MAX_VALUE: 'maxValue', | |
5439 | + MIN_VALUE: 'minValue', | |
5440 | + BG_COLOR: 'bgColor', | |
5441 | + WAVE_FIRST: 'waveFirst', | |
5442 | + WAVE_SECOND: 'waveSecond', | |
5443 | + WAVE_THIRD: 'waveThird', | |
5444 | + COMPONENT_TYPE: 'componentType' | |
5445 | + } | |
5446 | + | |
5447 | + const enumEl = { | |
5448 | + BG_COLOR_PICKER_EL: 'bgColorPickerEl', | |
5449 | + WAVE_FIRST: 'waveFirstEl', | |
5450 | + WAVE_SECOND: 'waveSecondEl', | |
5451 | + WAVE_THIRD: 'waveThirdEl', | |
5452 | + } | |
5453 | + | |
5454 | + const componentType = Sidebar.prototype.enumComponentType | |
5455 | + const flowmeterType = Sidebar.prototype.enumFlowmeterType | |
5456 | + const { TYPE } = getFlowmeterAttrKey() | |
5457 | + const cell = vertices[0] | |
5458 | + const isThemometerComponent = cell.getAttribute(TYPE) === flowmeterType.THERMOMETER | |
5459 | + | |
5460 | + if (isThemometerComponent) return | |
5461 | + | |
5462 | + const fragment = document.createDocumentFragment() | |
5463 | + const title = createTitle('流量计配置') | |
5464 | + $(title).addClass('override__title--default') | |
5465 | + | |
5466 | + const defaultPanel = createPanel() | |
5467 | + $(defaultPanel).addClass('override__panel--default') | |
5468 | + $(defaultPanel).append(`<div style="display: none;" class="layui-form-item data-source__component-select"><label class="layui-form-label">最小值</label><div class="layui-input-block"><input class="layui-input" name="${enumConst.COMPONENT_TYPE}" value="${componentType.FLOWMETER}" placeholder="组件类型"></div></div>`) | |
5469 | + // $(defaultPanel).append(`<div class="layui-form-item data-source__component-select"><label class="layui-form-label">最小值</label><div class="layui-input-block"><input class="layui-input" name="${enumConst.MIN_VALUE}" value="0" placeholder="请输入最小值"></div></div>`) | |
5470 | + // $(defaultPanel).append(`<div class="layui-form-item data-source__component-select"><label class="layui-form-label">最大值</label><div class="layui-input-block"><input class="layui-input" name="${enumConst.MAX_VALUE}" value="100" placeholder="请输入最大值"></div></div>`) | |
5471 | + $(defaultPanel).append(`<div style="display: ${isThemometerComponent ? 'none' : 'block'}" class="layui-form-item data-source__component-select"><label class="layui-form-label">背景色</label><div class="layui-input-block" style="display: flex; align-items: center;"><input style="border: none;" id="${enumEl.BG_COLOR_PICKER_EL}" type="color" name="${enumConst.BG_COLOR}" value="#8badcb" /></div></div>`) | |
5472 | + $(defaultPanel).append(`<div style="display: ${isThemometerComponent ? 'none' : 'block'}" class="layui-form-item data-source__component-select"><label class="layui-form-label">颜色一</label><div class="layui-input-block" style="display: flex; align-items: center;"><input style="border: none;" id="${enumEl.WAVE_FIRST}" type="color" name="${enumConst.WAVE_FIRST}" value="#4579e2" /></div></div>`) | |
5473 | + $(defaultPanel).append(`<div style="display: ${isThemometerComponent ? 'none' : 'block'}" class="layui-form-item data-source__component-select"><label class="layui-form-label">颜色二</label><div class="layui-input-block" style="display: flex; align-items: center;"><input style="border: none;" id="${enumEl.WAVE_SECOND}" type="color" name="${enumConst.WAVE_SECOND}" value="#3461c1" /></div></div>`) | |
5474 | + $(defaultPanel).append(`<div style="display: ${isThemometerComponent ? 'none' : 'block'}" class="layui-form-item data-source__component-select"><label class="layui-form-label">颜色三</label><div class="layui-input-block" style="display: flex; align-items: center;"><input style="border: none;" id="${enumEl.WAVE_THIRD}" type="color" name="${enumConst.WAVE_THIRD}" value="#2d55aa" /></div></div>`) | |
5475 | + | |
5476 | + | |
5477 | + fragment.append(title) | |
5478 | + fragment.append(defaultPanel) | |
5479 | + $(container).append(fragment) | |
5480 | + | |
5481 | + function init() { | |
5482 | + | |
5483 | + const refreshFn = echoRefreshFn | |
5484 | + echoRefreshFn = function () { | |
5485 | + refreshFn.apply(this) | |
5486 | + const { dataSources: [dataSource] = [] } = currentNodeData || {} | |
5487 | + form.val(CONTAINER_FILTER, dataSource?.additional || {}) | |
5488 | + } | |
5489 | + | |
5490 | + form.render() | |
5491 | + } | |
5492 | + | |
5493 | + init() | |
5494 | + } | |
5495 | + | |
5496 | + /** | |
5431 | 5497 | * @description 是否是折线图 |
5432 | 5498 | * @param {boolean} isLineChart |
5433 | 5499 | */ |
... | ... | @@ -5900,6 +5966,7 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
5900 | 5966 | } |
5901 | 5967 | const { field } = data |
5902 | 5968 | const value = getValueOnSubmit(field) |
5969 | + if (!value) return | |
5903 | 5970 | await to(autoSaveGraphInfo()) |
5904 | 5971 | const [err, res] = await to(ConfigurationNodeApi.updateNodeInfo(value)) |
5905 | 5972 | if (err) return |
... | ... | @@ -5927,12 +5994,13 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
5927 | 5994 | [componentType.VIDEO]: getVideoSubmitValue, |
5928 | 5995 | [componentType.SWITCH]: getSwitchSubmitValue, |
5929 | 5996 | [componentType.PARAMS_SETTING_BUTTON]: getSwitchSubmitValue, |
5930 | - [componentType.IMAGE]: getSubmitValue | |
5997 | + [componentType.IMAGE]: getSubmitValue, | |
5998 | + [componentType.FLOWMETER]: getFlowmeterSubmitValue, | |
5931 | 5999 | } |
5932 | 6000 | |
5933 | 6001 | const cell = vertices[0] |
5934 | 6002 | const type = graph.getAttributeForCell(cell, basicAttr.COMPONENT_TYPE) |
5935 | - return renderMapping[type]?.(field) || {} | |
6003 | + return renderMapping[type]?.(field) || false | |
5936 | 6004 | |
5937 | 6005 | function getSubmitValue(field) { |
5938 | 6006 | const ENABLED_FLAG = 'on' |
... | ... | @@ -6062,6 +6130,47 @@ DataFormatPanel.prototype.addDataFont = function (container) { |
6062 | 6130 | } |
6063 | 6131 | return value |
6064 | 6132 | } |
6133 | + | |
6134 | + function getFlowmeterSubmitValue(field = {}) { | |
6135 | + const additionalKey = HandleDataSource.enumConst | |
6136 | + const minValue = field[additionalKey.MIN_VALUE] | |
6137 | + const maxValue = field[additionalKey.MAX_VALUE] | |
6138 | + | |
6139 | + if ([minValue, maxValue].some(item => isNaN(item))) { | |
6140 | + UseLayUi.topErrorMsg('最大值或最小值不是一个数字!') | |
6141 | + return false | |
6142 | + } | |
6143 | + | |
6144 | + if (Number(minValue) > Number(maxValue)) { | |
6145 | + UseLayUi.topErrorMsg('最小值大于最大值!') | |
6146 | + return false | |
6147 | + } | |
6148 | + | |
6149 | + const value = { | |
6150 | + configurationId, | |
6151 | + contentId: currentPageId.id, | |
6152 | + nodeId: graphId, | |
6153 | + [enumCategory.ACT]: [], | |
6154 | + [enumCategory.EVENT]: [], | |
6155 | + [enumCategory.DATA_SOURCE]: { | |
6156 | + [enumDataSourceConst.ORG_ID]: field[enumDataSourceConst.ORG_ID], | |
6157 | + [enumDataSourceConst.DEVICE_ID]: field[enumDataSourceConst.DEVICE_ID], | |
6158 | + [enumDataSourceConst.DEVICE_TYPE]: field[enumDataSourceConst.DEVICE_TYPE], | |
6159 | + [enumDataSourceConst.DEVICE_PROFILE_ID]: field[enumDataSourceConst.DEVICE_PROFILE_ID], | |
6160 | + [enumDataSourceConst.ATTR]: field[enumDataSourceConst.ATTR], | |
6161 | + [enumDataSourceConst.ADDITIONAL]: { | |
6162 | + [additionalKey.COMPONENT_TYPE]: field[additionalKey.COMPONENT_TYPE], | |
6163 | + [additionalKey.MIN_VALUE]: field[additionalKey.MIN_VALUE], | |
6164 | + [additionalKey.MAX_VALUE]: field[additionalKey.MAX_VALUE], | |
6165 | + [additionalKey.BG_COLOR]: field[additionalKey.BG_COLOR], | |
6166 | + [additionalKey.WAVE_FIRST_COLOR]: field[additionalKey.WAVE_FIRST_COLOR], | |
6167 | + [additionalKey.WAVE_SECOND_COLOR]: field[additionalKey.WAVE_SECOND_COLOR], | |
6168 | + [additionalKey.WAVE_THIRD_COLOR]: field[additionalKey.WAVE_THIRD_COLOR], | |
6169 | + } | |
6170 | + }, | |
6171 | + } | |
6172 | + return value | |
6173 | + } | |
6065 | 6174 | } |
6066 | 6175 | |
6067 | 6176 | /** |
... | ... | @@ -13660,7 +13769,7 @@ class DispatchCenter { |
13660 | 13769 | subList.forEach(item => { |
13661 | 13770 | const { dataOrigin, additional } = item |
13662 | 13771 | if (dataOrigin === 'dataSources') { |
13663 | - if (additional) { | |
13772 | + if (additional && (additional || {})?.dataType ) { | |
13664 | 13773 | const { dataType } = additional || {} |
13665 | 13774 | if (dataType === HandleDataSource.enumDataBindType.REAL) { |
13666 | 13775 | this.dataSourceHandlerInstance.updateRealTimeDataSource(message, item) |
... | ... | @@ -13678,10 +13787,6 @@ class DispatchCenter { |
13678 | 13787 | handleFunction(message, item) |
13679 | 13788 | } |
13680 | 13789 | }) |
13681 | - // this.subscribeEvent(cmdId, this.updateCommonDataSource.bind(this)) | |
13682 | - return | |
13683 | - // const { subscriptionId, data } = message | |
13684 | - // DispatchCenter.instance.publishEvent(subscriptionId, data, message, event, ws) | |
13685 | 13790 | } |
13686 | 13791 | |
13687 | 13792 | /** |
... | ... | @@ -13712,6 +13817,40 @@ class DispatchCenter { |
13712 | 13817 | if (!id) return |
13713 | 13818 | const [err, res] = await to(ConfigurationNodeApi.getConfigurationInfo('CONTENT', id)) |
13714 | 13819 | this.contentData = res |
13820 | + this.afterGetContentDataNode() | |
13821 | + } | |
13822 | + | |
13823 | + afterGetContentDataNode() { | |
13824 | + setTimeout(() => { | |
13825 | + const componentType = Sidebar.prototype.enumComponentType | |
13826 | + const flowmeterComponent = this.contentData.dataSources.filter(item => item.additional && (item.additional || {}).componentType === componentType.FLOWMETER) | |
13827 | + const { MIN_VALUE, MAX_VALUE, BG_COLOR, WAVE_FIRST_COLOR, WAVE_SECOND_COLOR, WAVE_THIRD_COLOR } = HandleDataSource.enumConst | |
13828 | + flowmeterComponent.forEach(item => { | |
13829 | + const { nodeId, additional } = item | |
13830 | + const { bgColor, maxValue, minValue, waveFirst, waveSecond, waveThird } = additional || {} | |
13831 | + const cell = this.graph?.getCellsById([nodeId])?.[0] | |
13832 | + if (cell) { | |
13833 | + cell.setAttribute(BG_COLOR, bgColor) | |
13834 | + cell.setAttribute(MIN_VALUE, minValue) | |
13835 | + cell.setAttribute(MAX_VALUE, maxValue) | |
13836 | + cell.setAttribute(WAVE_FIRST_COLOR, waveFirst) | |
13837 | + cell.setAttribute(WAVE_SECOND_COLOR, waveSecond) | |
13838 | + cell.setAttribute(WAVE_THIRD_COLOR, waveThird) | |
13839 | + | |
13840 | + const { UUID } = getFlowmeterAttrKey() | |
13841 | + const id = cell.getAttribute(UUID) | |
13842 | + | |
13843 | + const element = document.getElementById(id) | |
13844 | + | |
13845 | + if (element) { | |
13846 | + element.querySelectorAll(`.${BG_COLOR}`).forEach(item => item.style.fill = bgColor) | |
13847 | + element.querySelectorAll(`.${WAVE_FIRST_COLOR}`).forEach(item => item.style.fill = waveFirst) | |
13848 | + element.querySelectorAll(`.${WAVE_SECOND_COLOR}`).forEach(item => item.style.fill = waveSecond) | |
13849 | + element.querySelectorAll(`.${WAVE_THIRD_COLOR}`).forEach(item => item.style.fill = waveThird) | |
13850 | + } | |
13851 | + } | |
13852 | + }) | |
13853 | + }, 10); | |
13715 | 13854 | } |
13716 | 13855 | |
13717 | 13856 | sendSubscribeMessage() { |
... | ... | @@ -14043,7 +14182,42 @@ class HandleDataSource { |
14043 | 14182 | /** |
14044 | 14183 | * @description 属性名称 |
14045 | 14184 | */ |
14046 | - ATTR_NAME: 'attrName' | |
14185 | + ATTR_NAME: 'attrName', | |
14186 | + | |
14187 | + /** | |
14188 | + * @description 组件类型 | |
14189 | + */ | |
14190 | + COMPONENT_TYPE: 'componentType', | |
14191 | + | |
14192 | + /** | |
14193 | + * @description 流量计最大值 | |
14194 | + */ | |
14195 | + MAX_VALUE: 'maxValue', | |
14196 | + | |
14197 | + /** | |
14198 | + * @description 流量计最小值 | |
14199 | + */ | |
14200 | + MIN_VALUE: 'minValue', | |
14201 | + | |
14202 | + /** | |
14203 | + * @description 流量计背景颜色 | |
14204 | + */ | |
14205 | + BG_COLOR: 'bgColor', | |
14206 | + | |
14207 | + /** | |
14208 | + * @description 流量计颜色一 | |
14209 | + */ | |
14210 | + WAVE_FIRST_COLOR: 'waveFirst', | |
14211 | + | |
14212 | + /** | |
14213 | + * @description 流量计颜色二 | |
14214 | + */ | |
14215 | + WAVE_SECOND_COLOR: 'waveSecond', | |
14216 | + | |
14217 | + /** | |
14218 | + * @description 流量计颜色三 | |
14219 | + */ | |
14220 | + WAVE_THIRD_COLOR: 'waveThird', | |
14047 | 14221 | } |
14048 | 14222 | |
14049 | 14223 | |
... | ... | @@ -14074,8 +14248,6 @@ class HandleDataSource { |
14074 | 14248 | |
14075 | 14249 | constructor(DispatchInstance) { |
14076 | 14250 | this.DispatchInstance = DispatchInstance |
14077 | - // this.generatorCommonDataSourceMapping() | |
14078 | - // this.generatorChartDataSourceMapping() | |
14079 | 14251 | } |
14080 | 14252 | |
14081 | 14253 | get graph() { |
... | ... | @@ -14114,76 +14286,6 @@ class HandleDataSource { |
14114 | 14286 | } |
14115 | 14287 | |
14116 | 14288 | /** |
14117 | - * @description 生成普通数据源绑定映射关系 | |
14118 | - * @param dataSources | |
14119 | - * @return {{cmdId: number, entityType: string, keys: *, scope: string, entityId: *}[]} | |
14120 | - */ | |
14121 | - generatorCommonDataSourceMapping() { | |
14122 | - const msg = this.commonDataSourceBindList.map((datum) => { | |
14123 | - const { deviceId, attr, nodeId, slaveDeviceId } = datum | |
14124 | - const cmdId = this.getCmdId(nodeId) | |
14125 | - const sendMsgTemplate = { | |
14126 | - entityType: "DEVICE", | |
14127 | - entityId: slaveDeviceId ? slaveDeviceId : deviceId, | |
14128 | - scope: "LATEST_TELEMETRY", | |
14129 | - cmdId, | |
14130 | - keys: attr, | |
14131 | - } | |
14132 | - this.dataSourceNodeMapping.set(nodeId, datum) | |
14133 | - this.subscribeEvent(cmdId, this.updateCommonDataSource.bind(this)) | |
14134 | - return sendMsgTemplate | |
14135 | - }) | |
14136 | - const { REAL } = HandleDataSource.enumDataBindType | |
14137 | - if (msg.length) this.sendMsg({ [REAL]: msg }) | |
14138 | - } | |
14139 | - | |
14140 | - | |
14141 | - /** | |
14142 | - * @description 图表数据源绑定关系 | |
14143 | - * @param {any[]} dataSource | |
14144 | - */ | |
14145 | - generatorChartDataSourceMapping() { | |
14146 | - const realList = [] | |
14147 | - const historyList = [] | |
14148 | - const { HISTORY, REAL } = HandleDataSource.enumDataBindType | |
14149 | - const { STARTTs, ENDTs } = HandleDataSource.enumConst | |
14150 | - for (const item of this.chartDataSourceBindList) { | |
14151 | - const { additional = {}, deviceId, attr, nodeId, slaveDeviceId } = item | |
14152 | - if (!attr) continue | |
14153 | - const { agg, interval = 1000, dataType, effectScope = 0 } = additional | |
14154 | - const cmdId = this.getCmdId(nodeId) | |
14155 | - const template = { | |
14156 | - entityType: "DEVICE", | |
14157 | - entityId: slaveDeviceId ? slaveDeviceId : deviceId, | |
14158 | - cmdId, | |
14159 | - interval: Number(interval), | |
14160 | - agg, | |
14161 | - keys: attr, | |
14162 | - } | |
14163 | - let scope = isNaN(effectScope) ? 0 : Number(effectScope) | |
14164 | - if (dataType === HISTORY) { | |
14165 | - template[STARTTs] = Date.now() - scope | |
14166 | - template[ENDTs] = Date.now() | |
14167 | - historyList.push(template) | |
14168 | - this.subscribeEvent(cmdId, (message) => { | |
14169 | - this.updateHistoryDataSource(message, agg) | |
14170 | - }) | |
14171 | - } | |
14172 | - else if (dataType === REAL) { | |
14173 | - template[STARTTs] = Date.now() - scope | |
14174 | - // template['timeWindow'] = interval | |
14175 | - realList.push(template) | |
14176 | - this.subscribeEvent(cmdId, (message) => { | |
14177 | - this.updateRealTimeDataSource(message, agg) | |
14178 | - }) | |
14179 | - } | |
14180 | - this.dataSourceNodeMapping.set(nodeId, item) | |
14181 | - } | |
14182 | - | |
14183 | - if (historyList.length || realList.length) this.sendMsg({ [HISTORY]: historyList, [REAL]: realList }) | |
14184 | - } | |
14185 | - | |
14186 | - /** | |
14187 | 14289 | * @description 订阅事件 绑定回调 |
14188 | 14290 | * @param eventName |
14189 | 14291 | * @param callback |
... | ... | @@ -14197,12 +14299,20 @@ class HandleDataSource { |
14197 | 14299 | * @param {} message |
14198 | 14300 | */ |
14199 | 14301 | updateCommonDataSource(message, record) { |
14302 | + console.log('enter') | |
14200 | 14303 | const { nodeId, attr } = record |
14201 | - const node = this.getNodeByCmdId(nodeId) | |
14304 | + const node = this.getNodeByNodeId(nodeId) | |
14305 | + const { data } = message | |
14306 | + const type = this.getComponentType(node) | |
14307 | + | |
14308 | + if (node && type === this.componentType.FLOWMETER) { | |
14309 | + this.handleFlowmeterComponent(message, record) | |
14310 | + return | |
14311 | + } | |
14202 | 14312 | |
14313 | + // 需要刷新页面 | |
14203 | 14314 | node && this.updatePage(() => { |
14204 | - const { data } = message | |
14205 | - const type = this.getComponentType(node) | |
14315 | + | |
14206 | 14316 | if (type === this.componentType.SWITCH) { |
14207 | 14317 | this.handleSwitchComponent(message, record) |
14208 | 14318 | return |
... | ... | @@ -14232,7 +14342,7 @@ class HandleDataSource { |
14232 | 14342 | handleSwitchComponent(message, record) { |
14233 | 14343 | const { data = {} } = message |
14234 | 14344 | const { nodeId, attr } = record |
14235 | - const node = this.getNodeByCmdId(nodeId) | |
14345 | + const node = this.getNodeByNodeId(nodeId) | |
14236 | 14346 | const [[_timespan, receiveValue] = []] = data[attr] || [] |
14237 | 14347 | const switchConfig = this.DispatchInstance.contentData.act.find(item => item.id === nodeId && item.type === 'SWITCH') |
14238 | 14348 | const { condition = [] } = switchConfig || {} |
... | ... | @@ -14273,11 +14383,46 @@ class HandleDataSource { |
14273 | 14383 | |
14274 | 14384 | } |
14275 | 14385 | |
14386 | + handleFlowmeterComponent(message, record) { | |
14387 | + const { data = {} } = message | |
14388 | + if (!data) return | |
14389 | + const { nodeId, attr } = record | |
14390 | + const node = this.getNodeByNodeId(nodeId) | |
14391 | + | |
14392 | + let [[_timespan, receiveValue] = []] = data[attr] || [] | |
14393 | + const { UUID, TYPE } = getFlowmeterAttrKey() | |
14394 | + const type = node.getAttribute(TYPE) | |
14395 | + const flowmeterType = Sidebar.prototype.enumFlowmeterType | |
14396 | + const id = node.getAttribute(UUID) | |
14397 | + const element = document.getElementById(id) | |
14398 | + const bindData = this.getBindData(nodeId) | |
14399 | + const { additional } = bindData || {} | |
14400 | + const { maxValue, minValue } = additional || {} | |
14401 | + | |
14402 | + receiveValue = isNaN(receiveValue) ? 0 : Number(receiveValue) | |
14403 | + console.log('enter') | |
14404 | + if (element) { | |
14405 | + if (type === flowmeterType.CIRCLE || type === flowmeterType.RECT) { | |
14406 | + const element = document.getElementById(id).querySelector('svg') | |
14407 | + element.style.setProperty('--value', receiveValue) | |
14408 | + } | |
14409 | + if (type === flowmeterType.THERMOMETER) { | |
14410 | + const element = document.getElementById(id).querySelector('svg') | |
14411 | + const range = 140 | |
14412 | + const ratio = (190 - 15) / range | |
14413 | + receiveValue = receiveValue >= 0 ? receiveValue + 20 : 20 - Math.abs(receiveValue) | |
14414 | + receiveValue = 190 - receiveValue * ratio | |
14415 | + receiveValue = receiveValue < 15 ? 15 : receiveValue | |
14416 | + element.style.setProperty('--value', receiveValue) | |
14417 | + } | |
14418 | + } | |
14419 | + } | |
14420 | + | |
14276 | 14421 | handleParamSettingButton(message, record) { |
14277 | 14422 | const { data = {} } = message |
14278 | 14423 | if (!data) return |
14279 | 14424 | const { nodeId, attr } = record |
14280 | - const node = this.getNodeByCmdId(nodeId) | |
14425 | + const node = this.getNodeByNodeId(nodeId) | |
14281 | 14426 | const [[_timespan, receiveValue] = []] = data[attr] || [] |
14282 | 14427 | this.updatePage(() => { |
14283 | 14428 | node.setAttribute('label', `<button class="param-setting-button">${receiveValue}</button>`) |
... | ... | @@ -14287,7 +14432,7 @@ class HandleDataSource { |
14287 | 14432 | handleImageComponent(message, record) { |
14288 | 14433 | const { data = {} } = message |
14289 | 14434 | const { nodeId, attr } = record |
14290 | - const node = this.getNodeByCmdId(nodeId) | |
14435 | + const node = this.getNodeByNodeId(nodeId) | |
14291 | 14436 | const [[_timespan, receiveValue] = []] = data[attr] || [] |
14292 | 14437 | this.updatePage(() => { |
14293 | 14438 | node.setAttribute('label', `<img class="basic-component__image" alt="图片" src="${receiveValue}" />`) |
... | ... | @@ -14303,7 +14448,7 @@ class HandleDataSource { |
14303 | 14448 | const { data = {} } = message |
14304 | 14449 | const { nodeId, attr, additional = {} } = record |
14305 | 14450 | const { agg } = additional |
14306 | - const node = this.getNodeByCmdId(nodeId) | |
14451 | + const node = this.getNodeByNodeId(nodeId) | |
14307 | 14452 | if (!node) return |
14308 | 14453 | const enumConst = Sidebar.prototype.enumCellBasicAttribute |
14309 | 14454 | const chartInstanceMap = Sidebar.prototype.chartsInstanceMapping |
... | ... | @@ -14334,7 +14479,7 @@ class HandleDataSource { |
14334 | 14479 | const { data = {} } = message |
14335 | 14480 | const { nodeId, attr, additional = {} } = record |
14336 | 14481 | const { agg } = additional |
14337 | - const node = this.getNodeByCmdId(nodeId) | |
14482 | + const node = this.getNodeByNodeId(nodeId) | |
14338 | 14483 | if (!node) return |
14339 | 14484 | const enumConst = Sidebar.prototype.enumCellBasicAttribute |
14340 | 14485 | const chartInstanceMap = Sidebar.prototype.chartsInstanceMapping |
... | ... | @@ -14703,7 +14848,7 @@ class HandleDataSource { |
14703 | 14848 | * @param subscriptionId |
14704 | 14849 | * @return {*} |
14705 | 14850 | */ |
14706 | - getNodeByCmdId(nodeId) { | |
14851 | + getNodeByNodeId(nodeId) { | |
14707 | 14852 | // const nodeId = this.getNodeIdByCmdId(subscriptionId) |
14708 | 14853 | return this.contentAllCell.find(item => item.id === nodeId) |
14709 | 14854 | } | ... | ... |
... | ... | @@ -1682,8 +1682,10 @@ Graph.sanitizeHtml = function(value, editing) |
1682 | 1682 | return null; |
1683 | 1683 | }; |
1684 | 1684 | function idX(id) { return id }; |
1685 | - | |
1686 | - return html_sanitize(value, urlX, idX); | |
1685 | + // console.log(html_sanitize(value, urlX, idX)) | |
1686 | + // TODO THINGS_KIT 取消html标签限制 | |
1687 | + return value | |
1688 | + // return html_sanitize(value, urlX, idX); | |
1687 | 1689 | }; |
1688 | 1690 | |
1689 | 1691 | /** | ... | ... |
thermometer.svg
0 → 100644
1 | +<svg class="flowmeter-thermometer" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg" | |
2 | + style="--range: 4; --min: 50; --max: 70; --width: 500; --height: 500; --value: 50;"> | |
3 | + <style> | |
4 | + .flowmeter-thermometer { | |
5 | + width: calc(min(var(--width), var(--height)) * 1px); | |
6 | + height: calc(min(var(--width), var(--height)) * 1px); | |
7 | + } | |
8 | + | |
9 | + .thermometer-mercury-column { | |
10 | + y: var(--value); | |
11 | + } | |
12 | + | |
13 | + .tick-label { | |
14 | + font-size: 12px; | |
15 | + text-align: right; | |
16 | + overflow: hidden; | |
17 | + text-overflow: ellipsis; | |
18 | + color: #5b6b73; | |
19 | + } | |
20 | + | |
21 | + .thermometer-mercury-column { | |
22 | + transition: y .5s cubic-bezier(0.19, 1, 0.22, 1); | |
23 | + } | |
24 | + </style> | |
25 | + <defs> | |
26 | + <radialGradient id="thermometerdiv_meter_2" cx="50%" cy="50%" r="50%" fx="50%" fy="50%"> | |
27 | + <stop offset="0%" style="stop-color: rgb(230, 200, 200);"></stop> | |
28 | + <stop offset="90%" style="stop-color: rgb(230, 0, 0);"></stop> | |
29 | + </radialGradient> | |
30 | + <clipPath id="over"> | |
31 | + <rect width="100" height="190" x="100" y="10" /> | |
32 | + </clipPath> | |
33 | + </defs> | |
34 | + <circle r="9.25" cx="109" cy="14.25" style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136); stroke-width: 1px;"> | |
35 | + </circle> | |
36 | + <rect x="99.75" y="14.25" height="192.75" width="18.5" | |
37 | + style="shape-rendering: crispedges; fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136); stroke-width: 1px;"> | |
38 | + </rect> | |
39 | + <circle r="8.75" cx="109" cy="14.25" style="fill: rgb(255, 255, 255); stroke: none;"></circle> | |
40 | + <circle r="18" cx="109" cy="207" style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136);"></circle> | |
41 | + <rect x="100.25" y="14.25" height="192.75" width="17.5" | |
42 | + style="shape-rendering: crispedges; fill: rgb(255, 255, 255); stroke: none;"></rect> | |
43 | + <line class="thermometer-min-line" x1="99.75" x2="140.25" y1="165" y2="165" | |
44 | + style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispedges;"></line> | |
45 | + <text class="thermometer-min-label" x="120.25" y="168.46428571428572" dy="0.72em" | |
46 | + style="fill: rgb(0, 0, 230); font-size: 10px;">min</text> | |
47 | + <line class="thermometer-max-line" x1="99.75" x2="140.25" y1="40" y2="40" | |
48 | + style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispedges;"></line> | |
49 | + <text class="thermometer-max-label" x="120.25" y="35.285714285714306" | |
50 | + style="fill: rgb(230, 0, 0); font-size: 10px;">max</text> | |
51 | + <rect class="thermometer-mercury-column" x="104" y="15" width="10.5" height="190" | |
52 | + style="shape-rendering: crispedges; fill: rgb(230, 0, 0);" clip-path="url(#over)"></rect> | |
53 | + <circle r="13" cx="109" cy="207" | |
54 | + style="fill: url("#thermometerdiv_meter_2"); stroke: rgb(230, 0, 0); stroke-width: 2px;"></circle> | |
55 | + <foreignObject> | |
56 | + <div></div> | |
57 | + </foreignObject> | |
58 | + <g class="thermometer-temperature-axis" transform="translate(99.75,0)" fill="none" font-size="10" | |
59 | + font-family="sans-serif" text-anchor="end"> | |
60 | + <g class="tick" opacity="1" transform="translate(0,190)"> | |
61 | + <line stroke="currentColor" x2="-7" | |
62 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
63 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
64 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">-20</div> | |
65 | + </foreignObject> | |
66 | + </g> | |
67 | + <g class="tick" opacity="1" transform="translate(0,165)"> | |
68 | + <line stroke="currentColor" x2="-7" | |
69 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
70 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
71 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">0</div> | |
72 | + </foreignObject> | |
73 | + </g> | |
74 | + <g class="tick" opacity="1" transform="translate(0,140)"> | |
75 | + <line stroke="currentColor" x2="-7" | |
76 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
77 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
78 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">20</div> | |
79 | + </foreignObject> | |
80 | + </g> | |
81 | + <g class="tick" opacity="1" transform="translate(0,115)"> | |
82 | + <line stroke="currentColor" x2="-7" | |
83 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
84 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
85 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">40</div> | |
86 | + </foreignObject> | |
87 | + </g> | |
88 | + <g class="tick" opacity="1" transform="translate(0,90)"> | |
89 | + <line stroke="currentColor" x2="-7" | |
90 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
91 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
92 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">60</div> | |
93 | + </foreignObject> | |
94 | + </g> | |
95 | + <g class="tick" opacity="1" transform="translate(0,65)"> | |
96 | + <line stroke="currentColor" x2="-7" | |
97 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
98 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
99 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">80</div> | |
100 | + </foreignObject> | |
101 | + </g> | |
102 | + <g class="tick" opacity="1" transform="translate(0,40)"> | |
103 | + <line stroke="currentColor" x2="-7" | |
104 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
105 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
106 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">100</div> | |
107 | + </foreignObject> | |
108 | + </g> | |
109 | + <g class="tick" opacity="1" transform="translate(0,15)"> | |
110 | + <line stroke="currentColor" x2="-7" | |
111 | + style="stroke: rgb(136, 136, 136); shape-rendering: crispedges; stroke-width: 1px;"></line> | |
112 | + <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20"> | |
113 | + <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">120</div> | |
114 | + </foreignObject> | |
115 | + </g> | |
116 | + </g> | |
117 | +</svg> | ... | ... |