From 55bff6fca3918b84129d8fca975e020f14519957 Mon Sep 17 00:00:00 2001 From: Celeste Date: Sat, 18 Feb 2023 21:00:48 +0800 Subject: [PATCH] =?UTF-8?q?[=E5=89=8D=E5=8F=B0]=20=E7=B3=BB=E7=B5=B1?= =?UTF-8?q?=E7=9B=A3=E6=8E=A7=20=E9=96=8B=E9=97=9C=E7=87=88=20|=20=20?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=20=E7=B8=AE=E7=9F=AD=E7=95=B0=E5=B8=B8?= =?UTF-8?q?=E7=B7=A8=E8=99=9F=20|=20=E8=83=BD=E6=BA=90=E7=AE=A1=E7=90=86?= =?UTF-8?q?=20=E6=96=87=E5=AD=97=E4=BF=AE=E6=AD=A3=20|=20=E6=AD=B7?= =?UTF-8?q?=E5=8F=B2=E8=B3=87=E6=96=99=20=E9=82=8A=E6=8F=90=E6=96=87?= =?UTF-8?q?=E5=AD=97=E4=BD=8D=E7=BD=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Frontend/_alert.html | 8 +- Frontend/_energyManagement.html | 1703 +++++++++++---------- Frontend/_historyData.html | 815 +++++----- Frontend/_operation.html | 2 +- Frontend/_sysMonAll.html | 17 +- Frontend/_sysMonFloor.html | 11 + Frontend/index.html | 2497 ++++++++++--------------------- Frontend/js/forge/forgemodel.js | 57 +- 8 files changed, 2100 insertions(+), 3010 deletions(-) diff --git a/Frontend/_alert.html b/Frontend/_alert.html index 98cc5b4..acf3e2a 100644 --- a/Frontend/_alert.html +++ b/Frontend/_alert.html @@ -228,7 +228,7 @@ $('input[type=checkbox][data-type=sub]').on('click', function () { if (!pageAct.selAllSysSub) { - console.log(this); + // console.log(this); pageAct.selAllSysSub = true; $.each($('input[type=checkbox][data-type=sub]:checked'), function (i, v) { @@ -646,6 +646,7 @@ let tag = "#alertTable"; $.each(data, function (i, v) { + // console.log(v.uuid.$val, v.uuid) v.formId = AlertList(v.uuid.$val || v.uuid); }); @@ -669,6 +670,9 @@ { "title": "異常ID", "data": "uuid", + render: (data) => { + return data.split("-")[0] + } }, { "title": "異常類別", @@ -788,7 +792,7 @@ function selOpeFir() { let url = baseApiUrl + "/operation/OpeFirSel"; objSendData.Data = { sub_system_tag: $('input[data-type=sub]').map(function (i, v) { return $(v).prop('id'); }).toArray() }; - console.log(objSendData.Data) + // console.log(objSendData.Data) ytAjax = new YourTeam.Ajax(url, objSendData, function (res) { if (!res || res.code != "0000" || !res.data) { diff --git a/Frontend/_energyManagement.html b/Frontend/_energyManagement.html index c16a3ac..be316fb 100644 --- a/Frontend/_energyManagement.html +++ b/Frontend/_energyManagement.html @@ -1,283 +1,286 @@ 
-
-
-
- - - - -
- -
-
-
-
- -
-
-
-

- - 用電狀況 -

+

運維管理

+
+
+
+ + + +
-
-
-
-

今日耗電量 kWh

-
- -
- -
-
-
-
-

用電比較

- -
- -
-
-
-
-
-
-
-
-
-
-
-

自動需量管理

+
+
+
- -
-
-
-

- 契約容量 - kW -

-

- 警戒容量 - kW -

-

- 復歸值 - kW -

-
-
- -
-
-
-
-
- -
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
日期開始-結束卸載時長
minutes
預計卸載量
kW
是否啟用名稱功能
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
編號名稱建立人建立時間功能
1平台管理員王小明2022-05-02 12:08修改 刪除
2平台運維王小明2022-05-02 12:08 -
- - +
+
+
+

+ - 用電狀況 +

-
3客戶管理員王小明2022-05-02 12:08修改 刪除
4客戶運維王小明2022-05-02 12:08修改 刪除
-
+
+
+
+

今日耗電量 (kWh)

+
+ +
+ +
+
+
+
+

用電比較

+ +
+ + +
+
+
+
+
+
-
+
+
+
+
+
+

自動需量管理

+ + +
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
日期開始-結束卸載時長
minutes
預計卸載量
kW
是否啟用名稱功能
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
2022-09-0111:00:00
11:30:00
3040 啟用停車場單號照明修改
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
編號名稱建立人建立時間功能
1平台管理員王小明2022-05-02 12:08修改 刪除
2平台運維王小明2022-05-02 12:08 +
+ + +
+
3客戶管理員王小明2022-05-02 12:08修改 刪除
4客戶運維王小明2022-05-02 12:08修改 刪除
+
+
+
+
+
+ + +
-
- -
-
- - -
\ No newline at end of file diff --git a/Frontend/_historyData.html b/Frontend/_historyData.html index bdb5356..2801674 100644 --- a/Frontend/_historyData.html +++ b/Frontend/_historyData.html @@ -1,194 +1,193 @@
-
-
-
-
- - +

歷史資料

+ +
+
+
+
+ + +
+ + +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
- - -
-
-
-

歷史資料瀏覽

-
-
-
- - - -
-
-
-
- - -
-
-
-
- - -
-
- - -
- -
-
- -
-
- -
-
- -
-
-
- -
- -
\ No newline at end of file diff --git a/Frontend/_operation.html b/Frontend/_operation.html index aaf5212..93ef9ec 100644 --- a/Frontend/_operation.html +++ b/Frontend/_operation.html @@ -504,7 +504,7 @@ setDate(null, startdate, enddate); }); - $(`[onclick="setType(null)"]`).click(); + $(`[onclick="setType(2)"]`).click(); initDate(); event(); diff --git a/Frontend/_sysMonAll.html b/Frontend/_sysMonAll.html index 6b01074..c68267c 100644 --- a/Frontend/_sysMonAll.html +++ b/Frontend/_sysMonAll.html @@ -102,7 +102,7 @@ } myBaja.setSubscribeDevicesByBql(ordPath); myBaja.setSubscribeDevicesCallBack(function (data) { - + //console.log(data) let matchDevice = allDevList.filter(x => x.device_number == data.device_number_full)[0]; if (!matchDevice) { return false; @@ -126,6 +126,16 @@ let cloDevPoiName = matchDevice.device_close_point_name; let errDevPoiName = matchDevice.device_error_point_name; + if (data.point_name == "SSC") { + const lightOn = data.value.includes("true") + setLightOpenOrClose(lightOn, matchDevice.device_guid); + if (lightOn) { + setLightValues(matchDevice.device_guid, 200, 0xe1cf18); + } else { + setLightValues(matchDevice.device_guid, 0, 0xe1cf18); + } + } + if (data.point_name == "Temp") { heatMap?.changeTemp(data.device_number_full, !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0); let devIdx = allDevList.findIndex(x => x.device_number == data.device_number_full); @@ -406,7 +416,9 @@ "area_tag": pageAct.AreaTag, "building_tag": pageAct.buiTag, }, + selector: "[name=forgeViewer]", curDevice: { + ...device, roomDbId: !isNaN(parseInt(device.room_dbid)) ? parseInt(device.room_dbid) : -1, id: device.device_number, position: isJSON(device.device_coordinate_3d) ? JSON.parse(device.device_coordinate_3d) : {}, // x: 0, y: 25, z: -2.5 (3.35, -4.81, 12.88 @@ -576,7 +588,7 @@ var parentEle = ""; onEvent("autodesk:click:sprite", "[name=forgeViewer]", function (e, obj) { forgeUnFocusAll(); - let position = [obj.event.target.toolController.lastClickX, obj.event.target.toolController.lastClickY]; + let position = [obj.event.target.toolController.lastClickX - 100, obj.event.target.toolController.lastClickY - 100]; let devObj = obj.myData; let name = allDevList.filter(x => x.device_guid == devObj.device_guid)[0]?.full_name; devObj.full_name = name; @@ -589,7 +601,6 @@ }) onEvent("autodesk:complete:sprite", "[name=forgeViewer]", function (e, obj) { - $("#floDevList a[name=devItem]").each((idx, ele) => { let devNum = $(ele).data("number"); let dbid = obj.myDataList.filter(x => x.device_number == devNum)[0]?._dbId; diff --git a/Frontend/_sysMonFloor.html b/Frontend/_sysMonFloor.html index 51182ce..48b8ddd 100644 --- a/Frontend/_sysMonFloor.html +++ b/Frontend/_sysMonFloor.html @@ -459,6 +459,17 @@ currentData[devIdx]._temp = !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0; } + + if (data.point_name == "SSC") { + const lightOn = data.value.includes("true") + setLightOpenOrClose(lightOn, matchDevice.device_guid); + if (lightOn) { + setLightValues(matchDevice.device_guid, 200, 0xe1cf18); + } else { + setLightValues(matchDevice.device_guid, 0, 0xffffff); + } + } + if (data.point_name == norDevPoiName && data.value == matchDevice.device_normal_point_value) { //顯示正常燈號 $(`#${matchDevice.device_number}_status`).attr("data-light-type", "normal").data("light-type", "normal"); diff --git a/Frontend/index.html b/Frontend/index.html index 7480f5b..0b7aab4 100644 --- a/Frontend/index.html +++ b/Frontend/index.html @@ -1,1815 +1,856 @@ - - - +
+
+
+ - - - - Marketing Dashboard - Application Intel - SmartAdmin v4.5.1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- - - - - - -
- -
- - -
- -
-
-
    -
- - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

-
-
- - -
+ - - + var eveDayElecChart = null; + var eveWeekElecChart = null; + var worOrdErrChart = null; + var worOrdFinChart = null; + var errRecChart = null; + var errChkChart = null; + var loadedCnt = 0; + var chartDataCnt = { alarmCnt: 0, recCnt: 0, chkedErrCnt: 0, unChkedErrCnt: 0 }; - - - + var sysIconList = [ + { mainSys: "EE", subSys: "E1", iconClass: "./gif/E1_white.png" }, + { mainSys: "EE", subSys: "E2", iconClass: "./gif/E2_white.png" }, + { mainSys: "EE", subSys: "E3", iconClass: "./gif/E3_white.png" }, + { mainSys: "EE", subSys: "E4", iconClass: "./gif/E4-1_white.png" }, // 電表 + { mainSys: "LT", subSys: "L1", iconClass: "./gif/L1_white.png" }, + { mainSys: "LT", subSys: "L2", iconClass: "./gif/L2_white.png" },// 景觀照明 0131目前沒有 + { mainSys: "ME", subSys: "M1", iconClass: "./gif/M1_white.png" },// 儲冰 0131目前沒有 + { mainSys: "ME", subSys: "M5", iconClass: "./gif/M5-2_white.png" }, // 送排風 + { mainSys: "ME", subSys: "M8", iconClass: "./gif/M8_white.png" },// 排油煙0131目前沒有 + { mainSys: "ME", subSys: "M10", iconClass: "./gif/M10_white.png" }, + { mainSys: "ME", subSys: "M12", iconClass: "./gif/M12_white.png" }, + { mainSys: "ELEV", subSys: "EL", iconClass: "./gif/EL_white.png" }, + { mainSys: "FE", subSys: "F1", iconClass: "./gif/F1_white.png" }, + { mainSys: "FE", subSys: "F2", iconClass: "./gif/lamp_white.png" }, // 排煙 0131目前沒有 + { mainSys: "WP", subSys: "W1", iconClass: "./gif/W1_white.png" },// 電子水表0131目前沒有 + { mainSys: "WP", subSys: "W2", iconClass: "./gif/W2_white.png" }, + { mainSys: "WP", subSys: "P1", iconClass: "./gif/P1_white.png" }, + { mainSys: "S", subSys: "C", iconClass: "./gif/C_white.png" }, // CCTV + { mainSys: "S", subSys: "P", iconClass: "./gif/P_white.png" }, // 緊急求救 + { mainSys: "S", subSys: "R", iconClass: "./gif/R_white.png" }, // 門禁 + { mainSys: "P", subSys: "PSC", iconClass: "./gif/PSC_white.png" }, // 停管 + { mainSys: "W3", subSys: "W1", iconClass: "./gif/W3_white.png" },// 0131目前沒有 + ]; + var tempSysSubText = [ + { text: "電梯系統", mainSys: "ELEV", subSys: "EL", }, // 1 + { text: "空調系統", mainSys: "ME", subSys: "M10", }, // 2 + { text: "照明系統", mainSys: "LT", subSys: "L1", }, // 3 + { text: "環境感測設備", mainSys: "ME", subSys: "M12", }, // 4 + { text: "電錶系統", mainSys: "EE", subSys: "E4", }, // 5 + { text: "供水系統", mainSys: "WP", subSys: "W2", }, // 6 + { text: "高壓配電盤", mainSys: "EE", subSys: "E1", }, // 7 + { text: "汙廢水設備", mainSys: "WP", subSys: "P1", }, // 8 + { text: "低壓配電盤", mainSys: "EE", subSys: "E2", }, //9 + { text: "緊急發電機", mainSys: "EE", subSys: "E3", },//10 + { text: "消防設備", mainSys: "FE", subSys: "F1", }, //11 + { text: "CCTV系統", mainSys: "S", subSys: "C", }, //12 + { text: "門禁系統", mainSys: "S", subSys: "R", }, //13 + { text: "停管系統", mainSys: "P", subSys: "PSC", }, //14 + { text: "緊急求救系統", mainSys: "S", subSys: "P", }, //15 + { text: "送排風系統", mainSys: "ME", subSys: "M5", }, //16 + //{ text: "景觀照明系統", mainSys: "LT", subSys: "L2", }, + //{ text: "儲冰系統", mainSys: "ME", subSys: "M1", }, + // { text: "排油煙設備", mainSys: "ME", subSys: "M8", }, + //{ text: "排煙系統", mainSys: "FE", subSys: "F2", }, + //{ text: "電子水錶", mainSys: "WP", subSys: "W1", }, + // { text: "熱水系統", mainSys: "W3", subSys: "W1", }, + ]; - - - - - - + $(document).ready(function () { + $(loadEle).Loading("start"); + $(loadEle).Loading("close"); + show3DModel(); + getSubList(); + getFirstEletric(); + }); + function demoSubList() { + let isExiNames = $("#sysSubBtnList .dev-group button[id^=sysSubCardBtn]").toArray().map(x => $(x).text()); + let strHtml = ``; - - - + if (worOrdErrChart == null) { + worOrdErrChart = new Chart(worOrdErrChartCanvas, { + type: "doughnut", + data: worOrdErrChartData, + options: worOrdErrChartOptions + }) + } else { + worOrdErrChart.data.datasets.forEach((dataset) => { + dataset.data = datas; + }); + } - \ No newline at end of file + } + + // 圖表 - 工單已完成與工單未完成 (圓環圖) + function chartWorOrdFin(labels, datas) { + labels = ["工單已完成", "工單未完成"] + datas = [5, 9] + let worOrdFinChartCanvas = ctx = $('#worOrdFinChart').get(0).getContext('2d'); + + let worOrdFinChartData = { + labels: labels, + datasets: [ + { + label: '數量', + unit: '個', + fill: true, + backgroundColor: [color.danger._500, color.info._300], + data: datas, + } + ] + } + + let worOrdFinChartOptions = { + maintainAspectRatio: false, + responsive: true, + legend: { + display: true, + }, + tooltips: { + enabled: true, + }, + + + } + + if (worOrdFinChart == null) { + worOrdFinChart = new Chart(worOrdFinChartCanvas, { + type: "doughnut", + data: worOrdFinChartData, + options: worOrdFinChartOptions + }) + } else { + worOrdFinChart.data.datasets.forEach((dataset) => { + dataset.data = datas; + }); + } + + } + + // 從 baja 訂閱 左下角各系統小類異常狀態 + function getAlarmSub(data) { + $.each(data.data, (idx, alaObj) => { + if (alaObj.alarmClass.indexOf("_") != -1) { + let mainSubSys = alaObj.alarmClass.split("_").slice(0, 2).join("/"); + const img = $(`.btn-group.dev-group[data-id*='${mainSubSys}'] img`)[0]?.src.split('.') + const { length } = img + img[length - 1] = 'gif' + $(`.btn-group.dev-group[data-id*='${mainSubSys}'] img`)[0].src = img.join('.') + $(`.btn-group.dev-group[data-id*='${mainSubSys}'] img`).addClass("blink"); + } + }) + $(`.dev-group img.blink`).each((idx, ele) => { + let devPath = $(ele).parents(".dev-group").data("id"); + let sysPath = devPath.split("/").slice(3, 5).join("/"); + let alaDevPath = data.data.map(x => x.alarmClass?.split("_").slice(0, 2).join("/")); + if (alaDevPath.indexOf(sysPath) == -1) { + const img = $(`.btn-group.dev-group[data-id*='${sysPath}'] img`)[0]?.src.split('.') + const { length } = img + img[length - 1] = 'png' + $(`.btn-group.dev-group[data-id*='${sysPath}'] img`)[0].src = img.join('.') + $(ele).removeClass("blink"); + } + }) + } + + + + function show3DModel() { + launchViewerNoTools(pageAct.urn, (viewer) => { + let elevOption = { + selector: "#forgeViewer", + viewer: viewer, + ordPath: { + "area_tag": pageAct.AreaTag, + "building_tag": pageAct.buiTag, + }, + } + + // 電梯移動訂閱程序載入 + let forge3DElev = new Forge3DElevFull(elevOption); + forge3DElev.bajaEndCallback = function () { + endPageLoading(); + } + forge3DElev.init(); + }); + } + + $(window).on("timeout:5m", function () { + console.log("五分鐘更新") + getElectricBaja(); + }) + + onEvent("click", "button[id^=sysSubCardBtn]", function () { + let subSysTag = $(this).data("id"); + $(`#subSysBtn${subSysTag}`).click(); + }) + \ No newline at end of file diff --git a/Frontend/js/forge/forgemodel.js b/Frontend/js/forge/forgemodel.js index 435e3e0..8db7e22 100644 --- a/Frontend/js/forge/forgemodel.js +++ b/Frontend/js/forge/forgemodel.js @@ -748,7 +748,7 @@ async function testNewLight(dataList) { dataList.forEach((myData, index) => { const position = JSON.parse(myData.device_coordinate_3d); if (lightList.findIndex(x => x.device_guid == myData.device_guid) == -1) { - lightList.push({ dbid: myData.forge_dbid, device_guid: myData.device_guid, lightObject: new THREE.SpotLight(0xff0000, 200, 20, 0.6, 0.5, 10) }); + lightList.push({ dbid: myData.forge_dbid, device_guid: myData.device_guid, lightObject: new THREE.SpotLight(0xe1cf18, 200, 20, 0.6, 0.5, 10) }); } lightList[index].lightObject.position.set(position.x, position.y, position.z); @@ -795,7 +795,7 @@ async function addHotPoint(data) { //熱點 點擊事件註冊 viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked);// SPRITE_SELECTED - + // viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClickedOut); //viewer.addEventListener( // Autodesk.Viewing.SELECTION_CHANGED_EVENT, // onSelectionChange @@ -820,25 +820,13 @@ async function addHotPoint(data) { //---------------- 熱點點擊事件 -------------------- function onSpriteClicked(event) { event.hasStopped = true; - if (pageAct.sysSubTag === "M12" && event != undefined && event != null) { - if (event.dbId >= dbIdStart) { - changeColorForHotspot(event.dbId); - changeScaleForHotspot(event.dbId, false); - let myData = [this.curDevice].filter(x => x.forge_dbid == event.dbId)[0]; - moveViewToDevice(myData.forge_dbid);//移動視角至該設備 - - $(selector).trigger("autodesk:click:sprite", { event, myData }); - } else { - $(selector).trigger("autodesk:clickOut:sprite", { event }); - } - } if (event != undefined && event != null) { if (event.dbId >= dbIdStart) {//event.dbId > 0 && event.dbId < 19 // console.log(`Sprite clicked: ${event.dbId}`); for (let i = dbIdStart; i <= myDataList.length + 10; i++) { changeColorForHotspot(i); - changeScaleForHotspot(i, false); + changeScaleForHotspot(i, true); } let myData = myDataList.filter(x => x._dbId == event.dbId)[0]; if (lightList != undefined && lightList != null && lightList.length > 0) { @@ -848,6 +836,8 @@ async function addHotPoint(data) { } $(selector).trigger("autodesk:click:sprite", { event, myData }); } else { + changeColorForHotspot(event.dbId, null); + changeScaleForHotspot(event.dbId, false); $(selector).trigger("autodesk:clickOut:sprite", { event }); } @@ -860,6 +850,21 @@ async function addHotPoint(data) { } } + // function onSpriteClickedOut(event){ + // event.hasStopped = true; + // if (event != undefined && event != null) { + // if (event.dbId >= dbIdStart) { + // for (let i = dbIdStart; i <= myDataList.length + 10; i++) { + // changeColorForHotspot(event.dbId); + // changeScaleForHotspot(event.dbId, false); + // } + // let myData = myDataList.filter(x => x._dbId == event.dbId)[0]; + // debugger + // $(selector).trigger("autodesk:clickOut:sprite", { event }); + // } + // } + // } + //function onSelectionChange(event) { // if (event != undefined && event != null) { // const dbIds = event.dbIdArray; @@ -881,7 +886,7 @@ async function addHotPoint(data) { // 熱點 更換顏色 async function changeColorForHotspot(dbId, type = null) { const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - // console.log(dbId, dataVizExtn.viewableData.getViewableColor(dbId, false)) + console.log(dbId, dataVizExtn.viewableData.getViewableColor(dbId, false)) let spriteColorFocus = dataVizExtn.viewableData?.getViewableColor(dbId, false) || new THREE.Color(0xffffff); if (type == "focus" && pageAct.sysSubTag !== "M12") { spriteColorFocus = new THREE.Color(0x00ffe1); @@ -897,26 +902,6 @@ async function changeColorForHotspot(dbId, type = null) { } -// 熱點 更換顏色---環境感知器 -async function changeColorForSensorHotspot(dbId, temp) { - const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization"); - const temps = [new THREE.Color(0x0000ff), new THREE.Color(0x00ff00), new THREE.Color(0xffff00), new THREE.Color(0xff0000)] - let index = Math.floor(temp / 10); - if (index > 3) { - index = 3 - } - const viewablesToUpdate = dbId; - const color = temps[index] - - dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => { - return { - color: color, - }; - }); - console.log(dataVizExtn) -} - - // 熱點 更換大小 async function changeScaleForHotspot(dbId, type = true) { const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");