以下內容為 SaaS Composer 產品使用分享技術交流,可能依照版本不同而有使用上的差異。
SaaS Compoer 繪圖核心使用到 Hightopo SDK & 2D Editor & 3D Editor ,針對應用場域管理及數據綁定做二次開發加值。
由於使用的是標準網頁瀏覽器 javascript 語法與 canvas 技術,可以透過前端技術進行擴展開發客製的圖標、組件進行整合。

Frequently Asked Question

Examples

General

如何設定物件(Node)的 tag及取得物件

在物件屬性中進行設定 Tag. 若設定為 tag_name.

          
            dataModel.getDataByTag('tag_name')
          
        

取得 Node data 的方式除了透過 tag 之外,在事件傳入的 "data",也可直接獲取當前 Node Data。

如何取的GraphView物件

In 2D page (display.html) : graphView
In 3D page (scene.html) : g3d
In Overlay page (sceneAndDisplay.html) : graphView or g3d
Or

          
            commonViewUtil.getFileObjByFileName(dataRefreshUtil.currentFile).graphView
          
        

或是在每個事件 function 中傳入的 gvview
使用疊加層時盡量使用事件函數傳入的 graphview.

如何取的圖紙、場景dataModel

In 2D page (display.html) : dataModel
In 3D page (scene.html) : dataModel
In Overlay page (sceneAndDisplay.html) : dataModel
Or

          
            commonViewUtil.getFileObjByFileName(dataRefreshUtil.currentFile).dataModel
          
        

或是在每個事件 function 中傳入的 dm
或是從 graphview 物件下使用 graphview.dm()
使用疊加層時盡量使用事件函數傳入的 graphview 或是 dm.

物件屬性改值

可透過 dataModel.getDataByTag('tag_name') 取得物件,物件屬姓分為 property(p), style(s), attribute(a), 使用以下取的當前值:

            
              dataModel.getDataByTag('tagName').s('style_name')
              dataModel.getDataByTag('tagName').a('attribute_name')
              dataModel.getDataByTag('tagName')[ht.Default.getter('property_name')]();
            
          
使用以下設定當前值:
            
              dataModel.getDataByTag('tagName').s('style_name', value)
              dataModel.getDataByTag('tagName').a('attribute_name', value)
              dataModel.getDataByTag('tagName')[ht.Default.getter('property_name')](value);
            
          

物件(圖標)動態添加

          
            // 添加文字  
            var d = new ht.Text()
            d.s('text','AAA')
            dataModel.add(d)

            // 添加圖標  
            var node = new ht.Node();
            node.setImage('symbols/builtIn/fan/fan3.json'); // 加入圖標路徑  
            node.p({x:200,y:200})
            dataModel.add(da)
          
        

物件動態添加事件

          
            node.s({
              'interactive': true,
              'onClick': function(event, data, view) {
              }
            })
          
        

SVG顯示錯誤

SVG 中的內容如果不是向量圖形,而是 `image` 這種多png組成的, 在添加入HT編輯器時可能會出現無法顯示,進入到瀏覽模式時會看不見這張 svg。 此時請直接使用 png 進行貼圖。

          
            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="997" height="1217" viewBox="0 0 997 1217">
              <image id="图层_2" data-name="图层 2" x="111" y="62" width="742" height="1088" xlink:href="data:img/png;base64"/>
            </svg>
          
        

導出匯出場景、圖紙時,失敗

1. 如果只有特定圖紙無法匯出,可能是圖紙上物件中含有亂碼造成無法解析,請找出並移除該物件。
2. 如果是所有圖紙均無法匯出,可能是部屬空間資源不足。需要請平台調整部屬資源。

元素屬性變化事件監聽器

          
            dataModel.md(function(event) {
              //event格式:
              {
                property: "name",//发生变化的属性
                data: data,//属性发生变化的data
                oldValue: 0,//旧值
                newValue: 1//新值
              }
            });
          
        

Viewer 數據綁定相關資訊,含request、response

          
            // 使用已下可讀取到當前所有開啟過的圖紙數據綁定設定
            dataRefreshUtil.filesMap
            // 對應當前圖紙名稱
            dataRefreshUtil.currentFile
            // 收集所有數據綁定對照(上圖中)  
            collectSource
            // 發送取值前request整理(上圖中)
            reqCollect
            // 數據回應的response儲存(上圖中)  
            resCollect
          
        

HTML DOM元素和 canvas上的繪制圖形是兩個不同的層,它們無法交錯層疊。

HTML DOM(文檔對象模型)元素是網頁中的HTML元素,如文本、圖像、按鈕等, 它們是由HTML代碼創建的並且可以通過CSS樣式進行布局和樣式化。而 <canvas> 元素是一個HTML5提供的元素, 它是一個繪圖區域,可以通過JavaScript繪制2D圖形、圖像和動畫。 簡而言之,HTML DOM元素和<canvas>上的繪制圖形是兩個不同的層, 它們無法交錯層疊。具體原因是因為HTML DOM元素是由HTML代碼創建並渲染的, 它們是瀏覽器的文檔對象的一部分。而<canvas>元素是一個特殊的繪圖區域, 它是通過JavaScript繪制的,繪制的內容與HTML文檔無關,也無法直接與HTML DOM元素進行交互。 如果想要在<canvas>上繪制與HTML DOM元素交互的圖形,可以使用JavaScript繪制的方法, 例如使用繪制庫(如Canvas API)來實現繪圖效果,並通過JavaScript來響應用戶交互。但是, 繪制在<canvas>上的圖形不會影響到HTML DOM元素,它們仍然是分開的兩個層級,無法直接交錯疊加。 因此,如果想要在頁面中同時使用HTML DOM元素和<canvas>繪制圖形, 需要將它們分別放置在不同的位置,並理解它們是兩個獨立的層,無法直接交錯疊加。

腳本語法僅支持:javascript

頁面完全使用標準html, javascript語法,依瀏覽器支援進行渲染。
所有的開發技術請參考Javascript前端網頁進行學習。

透過生成json產生圖紙及數據綁訂

可將相關物件配置完成後,複製右下角的數據進行查看各屬性資訊。
依json格式生成新的json即可。

          
            使用api上傳可以呼叫 "POST /upload"
            Body:
            {
              path: scenes/****.json,
              content: { **數據json** }
            }
            注意需要登入"POST /api/login"後取得token才能呼叫驗證成功
            {
              "password": "******",
              "username": "******"
            }
          
        

資料綁定 Set Match,設定顏色不要用Direct feed

Direct feed 的功能是為了快速處理 0,1 與 true, false 對應使用
0 => false
1 => true
勾選 direct feed 則不需額外配置 true, false

不同 view HTML 頁面功能對應

HTML 功能 說明
display.html 2D 顯示 2D 預設預覽
scene.html 3D 顯示 3D 預設預覽
sceneAndDisplay.html 2D & 3D 疊加層顯示 預設預覽、選單開啟疊加層
view.html 2D 或 3D 顯示 選單預設,未開啟疊加層

非數值型屬性綁定數據或動態填資料


以下拉選單為例,需要的格式是 (label, value) 陣列資料。
可透過 script 動態填入相同格式的 json,達到動態換資料。
即可透過 fetch, XMLHttpRequest 等方式動態改動下拉選單內容

          
            data.a('ht.dataSource', [
              { 'label': 'tag 1', value: 'tag_name_1' },
              { 'label': 'tag 2', value: 'tag_name_2' }
            ])
          
        

不支持變量的數據源動態切換綁訂數據

1. 在 Userdefined 的數據綁定中,預先定義可能會使用到被切換的數據,以便在取值時會預先讀取。
2. 在綁定的數據的彈窗屬性裡修改"id",在標簽頁 Information > id。本例中修改為 test_change
3. 修改物件綁定的數據物件:

          
            dataRefreshUtil.filesMap.forEach((item) => {
              if (dataRefreshUtil.currentFile === item.filename) {
                  item.collectSource.forEach((obj) => {
                      if (obj.db.id === 'test_change') {
                          if (obj.db.targets[0].target === 'upper_0') {
                              obj.db.targets[0] = {sourceType: 'SimpleJson', formatType: 'timeseries', scDataType: 'value', target: 'upper_1'};
                          } else {
                              obj.db.targets[0] = {sourceType: 'SimpleJson', formatType: 'timeseries', scDataType: 'value', target: 'upper_0'};
                          }
                          console.log(obj.db.id, obj.db.targets[0].target)
                      }
                  })
              }
            })
          
        

修改 dataRefreshUtil.filesMap 中的 collectSource,找到對應物件的 ***target*** 並進行修改。
注意:不同數據源的 targets 物件格式可能不同,請依照個數據源參數進行改寫。
target物件中的必要欄位:

  • sourceType
  • formatType
  • scDataType
  • target



數據源的 datasourcetype 取得


在 Data source 列表中,點擊 "i" 會自動複製 datasourcetype。
這個名稱是數據源唯一識別 "id" 。
※ datasourceName 則是用戶自定義的名稱

Assets目錄支援格式

媒體類型:

  • png
  • gif
  • jpg
  • jpeg
  • svg
  • mp3
  • mp4
  • dxf
  • obj
  • mtl
  • 3ds
  • bin
  • fbx
  • hdr
  • gltf
  • glb

文字類型:

  • json
  • cob
  • htb
  • js
  • css
  • html
  • htm

頁面過場、轉場特效


此功能僅適用於 `3D & 2D 疊加層` 預覽介面.

          
            commonViewUtil.sceneTransitionInOutAnimated(currentFileName, newFileName, option)
          
          

- currentFileName: 當前檔案路徑 (ex. `displays/Acid Exhaust Fan and Scrubber 2.json`) - newFileName: 轉頁的檔案路徑 (ex. `displays/SpongFactory.json`) - option: 包含三個方法. (beforeAnimate, onUpdate, onEnd) - beforeAnimate(tempOutDiv, tempDiv) - onUpdate(tempOutDiv, tempDiv, idx) - onEnd() - tempOutDiv: 當前頁面的 `< div >` 區塊 - tempDiv: 新頁面的 `< div >` 區塊 - idx: 從 1 降到 0 的數字, 做動畫變換計算功能.

右方推入

          
            commonViewUtil.sceneTransitionInOutAnimated('displays/Acid Exhaust Fan and Scrubber.json', 'displays/SpongFactory.json')
          
        

客製化樣式範例

旋轉縮小、放大

          
            commonViewUtil.sceneTransitionInOutAnimated(
              'displays/SpongFactory.json',
              'scenes/building.json',
              {
                  beforeAnimate: function(tempOutDiv, tempDiv){
                      tempOutDiv.style.transform = 'scale(1,1) rotateZ(0deg)';
                      tempDiv.style.transform = 'scale(0,0) rotateZ(360deg)';
                  },
                  onUpdate: function(tempOutDiv, tempDiv, idx){
                      const reversIdx = (1 - idx)
                      const revers = 360 * (1 - idx)
                      const rotate = 360 * idx;
                      const scale = 1 * reversIdx * reversIdx;
                      if (idx >= 0.5) {
                          const s1 = (idx * 2 - 1)
                          const r1 = 360 * (1 - idx) 
                          tempOutDiv.style.transform = 'scale('+s1+','+s1+') rotateZ('+r1+'deg)';
                          tempDiv.style.transform = 'scale(0,0) rotateZ(360deg)';
                      }
                      if (idx <= 0.5) {
                          const s2 = (reversIdx * 2 - 1)
                          const r2 = 360 * (1 - reversIdx) 
                          tempOutDiv.style.transform = 'scale(0,0) rotateZ(360deg)';
                          tempDiv.style.transform = 'scale('+s2+','+s2+') rotateZ('+r2+'deg)';
                      }
                  }
              }
            )
          
        

淡出淡入 使用 CSS opacity

          
            commonViewUtil.sceneTransitionInOutAnimated('scenes/building.json', 'displays/Acid Exhaust Fan and Scrubber 2.json', {
              beforeAnimate: function(tempOutDiv, tempDiv){
                  tempOutDiv.style.opacity = 1;
                  tempDiv.style.opacity = 0;
              },
              onUpdate: function(tempOutDiv, tempDiv, idx){
                 if (idx >= 0.5) {
                     tempOutDiv.style.opacity = 2 * idx - 1;
                     tempDiv.style.opacity = 0;
                 }
                 if (idx <= 0.5) {
                     tempOutDiv.style.opacity = 0;
                     tempDiv.style.opacity = 2*(1-idx) - 1;
                 }
              }
            })
          
        

執行 Duration function時,使用 requestAnimationFrame 取代 setInterval

如果想要用 requestAnimationFrame執行動畫而不是 setInterval的話,可以添加 attribute 參數 custom.requestAnimationFrame。 一般情況下,使用者會透過修改 refresh time來加速執行期間的動畫更新,如果將refrash time設定到 0.01時, 建議可以改用 requestAnimationFrame 來取代。



          
            "custom.requestAnimationFrame": true
          
        

2D

2D map、video 等,與繪制圖形是兩個不同的層,它們無法交錯層疊。

          
            HTML DOM (文檔對象模型)元素是網頁中的 HTML 元素,如文本、圖像、按鈕等,
            它們是由 HTML 代碼創建的並且可以通過CSS樣式進行布局和樣式化。而 <canvas> 元素是一個 HTML5 提供的元素,
            它是一個繪圖區域,可以通過 JavaScript 繪制 2D 圖形、圖像和動畫。
            簡而言之, HTML DOM 元素和 <canvas> 上的繪制圖形是兩個不同的層,
            它們無法交錯層疊。具體原因是因為 HTML DOM 元素是由 HTML 代碼創建並渲染的,
            它們是瀏覽器的文檔對象的一部分。而 <canvas> 元素是一個特殊的繪圖區域,
            它是通過 JavaScript 繪制的,繪制的內容與 HTML 文檔無關,也無法直接與 HTML DOM 元素進行交互。
            如果想要在 <canvas> 上繪制與 HTML DOM 元素交互的圖形,可以使用 JavaScript 繪制的方法,
            例如使用繪制庫( 如Canvas API )來實現繪圖效果,並通過 JavaScript 來響應用戶交互。但是,
            繪制在 <canvas> 上的圖形不會影響到 HTML DOM 元素,它們仍然是分開的兩個層級,無法直接交錯疊加。
            因此,如果想要在頁面中同時使用 HTML DOM 元素和 <canvas> 繪制圖形,
            需要將它們分別放置在不同的位置,並理解它們是兩個獨立的層,無法直接交錯疊加。
        
        

2D 事件無法觸發

          
            點擊事件或其他事件無法被觸發,請確認物件是否有啟用。可交互(interactive)。
            如果只是針對單一事件無法觸發,請透過瀏覽器開發者工具確認是否有語法撰寫錯誤情況發生。
          
        

2D 整合Echart第三方擴充套件

第三方圖形可以參考: Echart Demo

在設定頁引入第三方套件。
https://cdn.jsdelivr.net/npm/echarts-liquidfill@3/dist/echarts-liquidfill.min.js


新建圖標,並且在Render HTML撰寫相關引用 Echart 的代碼,及設定可數據綁定的參數
在圖指引用之後即可在預覽時呈現。
需要注意 Echart 是使用獨立的 HTML 元件,不可與繪製的圖進行交錯排列。

          
            let value = data.a('value');
            if (value > 1) {
                value = (value % 100) / 100;
            } else if (value < 0) {
                value = 0
            }

            var option = {
              backgroundColor: '#fff',
              title: {
                left: 'center',
                bottom: 20,
                text: '申请方',
                textStyle: {
                  fontWeight: 'bold',
                  fontSize: 25,
                  color: '#333'
                },
                subtext: '满意度',
                subtextStyle: {
                  color: '#333'
                }
              },
              series: [
                {
                  type: "liquidFill",
                  name: '申请方',
                  radius: "85%",
                  center: ['50%', '45%'],
                  shape: "path://M657.462,490.835c-21.359-45.771-82.071-35.092-82.471,18.032-0.221,29.177,28.91,40.083,48.306,51.747,18.807,11.312,32.193,26.786,34.291,33.373,1.8-6.454,16.705-22.366,34.115-33.689,19.036-12.382,48.527-22.572,48.306-51.748C739.607,455.294,677.839,446.889,657.462,490.835Z",
                  data: [value, value, value], //datat
                  color: ['#fc8b8b'],
                  outline: {
                    show: false,
                  },
                  backgroundStyle: {
                    color: '#edd4d4',
                    borderColor: "#fff",
                    borderWidth: 1,
                    shadowColor: "rgba(0, 0, 0, 0.4)",
                    shadowBlur: 0,
                  },
                  label: {
                    normal: {
                      position: ["50%", "40%"],
                      formatter: () => {
                        return Math.round(value * 100) + '%'
                      },
                      textStyle: {
                        fontSize: 30,
                      },
                    },
                  },
                },
              ],
            };

            if (!cache.htmlView) {
                cache.htmlView = document.createElement('div');
                cache.htmlView.style.position = 'absolute';
                cache.htmlChart = echarts.init(cache.htmlView);

                // layoutHTML will be called when the data needs to be drawing
                cache.htmlView.layoutHTML = function() {
                    gv.layoutHTML(data, cache.htmlView, false);
                    cache.htmlChart.resize();
                };
            }

            // update data
            option.color = [data.a('lineColor1'), data.a('lineColor2')];
            option.textStyle = { color: data.a('textColor') };
            cache.htmlChart.setOption(option);

            // html for showing
            return cache.htmlView;
        
        

2D Table 圖標客製化欄位內容

可參考內建圖紙: displays/builtIn/table.json

或是參考 Technical Documentation 表格章節

2D webrtc 影像接入

可使用以下內建套件
1. 動態引入 /custom/libs/rision.js
2. 先建圖標
3. 添加 videoURL屬性
4. webrtc://172.xx.x.xx:xxxx/xxxxx/xxxx

          
            let videoURL = data.a('videoURL');
            var script = document.createElement("script");
            script.setAttribute("src", "/custom/libs/rision.js");
            document.getElementsByTagName('head')[0].appendChild(script);

            if (!cache.htmlView) {
                var video = cache.htmlView = document.createElement('video');
                video.setAttribute("controls", "controls")
                video.layoutHTML = function () {
                    gv.layoutHTML(data, video);
                };
            };

            var r = commonUtil.getParamFromURL('org_id');

            setTimeout(() => {
                const video = document.getElementsByTagName('video')[0];
                video.autoplay = true;
                video.muted = true;
                video.crossOrigin = 'anonymous';
                const risions = window.rison;
                let sdk = risions.SrsRtcPlayerAsync();
                if (video && videoURL) {
                    video.srcObject = sdk.stream;
                    sdk
                        .play(videoURL)
                        .then(function (session) {
                            console.log('🚀 ~ session:', session.code);
                        })
                        .catch(function (reason) {
                            console.log('🚀 ~ reason:', reason);
                            sdk.close();
                        });

                }
            }, 500)
            return cache.htmlView;
          
        

3D

圖紙步進距離設定

          
            g3d.setMoveStep(number)
            g3d.getMoveStep()
          
        

3D 貼皮重複 UV

要正確貼皮,圖片大小有限制, 贴图大小要是2的n次方,如: 128 * 256 = 27*28

3D 場景優化

場景可以從以下幾個方面優化:
1、讓設計師輕量化模型,對模型進行減面,不必要的細節不要精細建模,使用貼圖代替,ht的3d場景模型總面數不建議超過 200 萬面。
2、做批量優化:https://www.hightopo.com/guide/guide/core/batch/ht-batch-guide.html
3、節點做矢量緩存 node.s('texture.cache',true)

3D 模型簡化

Web 上撐不住那麽大模型,哪怕純裸寫 WebGL 繪制三角面極限也就在哪里,這種情況有幾條路:
1、簡化模型,這是最有效的,我們大部分外包的項目模型都會重新設計
2、業務分級,例如數據中心,打開機櫃再顯示里面的服務器和端口細節
3、算法上簡模的定制化
官網例子的模型基本都沒超過 10m,單個設備一般構建在 m 以內,甚至小到幾10k,定位的大部分還是運維的系統,用戶只需要看得清是個什麽樣的設備即可。
所以大部分情況下,用戶說有模型可以給我們用的項目,一般都可以直接告訴客戶,現有的模型只能做參考,
大部分情況下我們需要重新建模,因為用戶手頭的模型基本都是 SolidWorks 之類的工程建模模型,是非常精確的為了可制造生產的建模精度,但作為運維一般會極大的簡化建模。

3D obj模型大小超過20m,如何壓縮呢?

模型的大小是由模型的面數控制的,面數和模型大小成正比,需要設計師在建模軟件中對模型進行減面處理。

3D 調適訊息,效能資訊顯示

          
            // 2D
            graphView.showDebugTip();
            // 3D
            graph3dView.showDebugTip();
          
        

3D 如何複製內建obj模型進行修改。

開啟模型,依照模型路徑至assets目錄下將檔案匯出即可進行修改。
修改完成之後,請重新建立新的Model。
對應的貼皮圖檔紀錄在mtl檔中,需先下載後再找對應的檔案。

3D FBX 模型動態置換材質。

一般方式如果要置換模型材質需要動態產生模型,給予材質,並在場景上取代舊模型
比較簡易的方式是針對 Node 進行屬性替換,針對 matDef 屬性修改。
matDef 中的 key 值為 fbx 內部定義。

          
            dataModel.getDataByTag('aaa').s(
              'matDef',
              { 
                外墙: "materials/builtIn/building/brickPillar.json"
              }
            )
          
        

3D 看板文字解析度

默認讀取的是設備的 dpi , 不同設備 dpi 不同,
dpi 設置的比較低清晰度會較低。
可以使用 g3d.setDevicePixelRatio() 主動設置 dpi。
設置較大的貼圖縮放比例,也可提高清晰度。

          
            g3d.setDevicePixelRatio()
          
        

3D 看板不同系統文字長度問題

應該是不同系統電腦缺少了字體,導致獲取文本的長度不同,進行了換行。
可以適當調大寬度,或者取消自動換行。

3D 點擊平面物件添加標示

在平面上貼上道路貼皮
點選物件上道路的點,在該位置添加標示。

          
            const point = view.intersectObject(event,data)

            const node = new ht.Node()
            node.s3(30,30,30);
            node.setPosition3d(point.local.x, point.local.y + 30, point.local.z)
            view.dm().add(node)
          
        

3D 點擊物件高亮(highlight)

以通过node上的style属性highlight.mode单独控制高亮的模式
setHighlightMode: 设置当前高亮的模式,包括:disabled关闭高亮,selected选中高亮,hover悬浮高亮,style风格设置高亮
getHighlightMode: 获取当前高亮的模式,默认为style
setHighlightColor: 设置当前高亮的颜色
getHighlightColor: 获取当前高亮的颜色,默认为rgba(190, 210, 250, 1)
setHighlightWidth: 设置当前高亮的线宽
getHighlightWidth: 获取当前高亮的线宽,默认为0.8

          
            g3d.setHighlightMode('mouseover');
            g3d.setHighlightColor('#FEB64D');
            g3d.setHighlightWidth(3);
          
        

或是參考 hightopo 物体高亮效果

3D 選中物件變暗

節點選中變暗是因為選中亮度默認是 0.7,調整為 1 即可
不變暗,node.s("select.brightness", 1)

          
            node.s("select.brightness", 1)
          
        

或是參考 hightopo 風格

3D 中的2D圖標,添加tooltip

先在 3D 開啟場景添加

          
            g3d.setToolTipEnabled(false) 
          
        

在2D圖標的事件中添加

          
            ht.Default.showToolTip(event, 'AAAXrrX');
            ht.Default.hideToolTip()
          
        

Overlay

取得各層 graphview 或 dataModel

          
            可以透過每個事件function中傳入的gv,view,dm等參數取得。  
            graph2d = gv;
            之後可以從全域變數中提取,此方法可以避免因檔案複製路徑檔名不同而需要修改的問題。
            其次,可透過全域變數 "commonViewUtil.currentFiles" 取得當前所有開啟的圖紙場景物件,
            包含 graphView 與 dataModel ,使用此方式需要知道要操控的是哪個疊加層檔案名稱。
          
        

取得各層 graphview 或 dataModel

在要顯示 tooltip 的物件上添加 (move) 互動事件

          
            ht.Default.showToolTip(event, data.getToolTip())
          
        

在畫面額外特定 div 開啟圖紙

在圖紙中添加,DIV圖標`builtIn/html/div.json`
在 main content中加入下列 DIV 元素
設定DIV大小

          
            <div id="small" style="position:relative;width:100%;height:100%;min-height:100px;background:#F00;"></div>
          
        

添加一個按鈕,並設定`click`事件(代碼如下)

          
            var obj = {
              fileName: 'displays/dom1.json', 
              gvType: 'displays'
            }
            if(typeof commonViewUtil != 'undefined'){
                var exist = false;
                for(var i=0;i < commonViewUtil.currentFiles.length;i++){
                    if(commonViewUtil.currentFiles[i]['fileName'] == obj['fileName']){
                        commonViewUtil.currentFiles[i]['graphView'].addToDOM(document.getElementById('small'));
                        exist = true;
                    }
                }
                if(!exist){
                    commonViewUtil.appendDisplayToDOM(obj,{'parentViewId':'small'})
                }
              }
          
        
          

需要注意下方幾點: - 確認 `commonViewUtil` 是否存在,只有在擁有疊加層的頁面具有此API - 確認圖紙是否曾經被加載到畫面過,如果有則使用原有的 graphView - 如果圖紙是第一次被添加到畫面則使用`commonViewUtil.appendDisplayToDOM`,並設定`parentViewId`

使用疊加層時,編寫 script使用 graphView & dataModel方式

          

在 commonViewUtil.currentFiles 中,保存所有疊加層的圖紙資訊 依照 'fileName' 可以從 commonViewUtil.currentFiles 找到想要的圖紙 如果只有一層2D疊在3D畫面上,則

          
            commonViewUtil.currentFiles[0] 是 3D場景  
            commonViewUtil.currentFiles[1] 是 2D疊加層  
        
            commonViewUtil.currentFiles[0]['fileName']   圖紙的檔案名稱  
            commonViewUtil.currentFiles[0]['graphView']  圖紙的graphView  
            commonViewUtil.currentFiles[0]['dataModel']  圖紙的dataModel  
            commonViewUtil.currentFiles[0]['isLayer']    判斷是否為圖層  
          
        

全域的

          
            graphView = commonViewUtil.currentFiles[0]['graphView']  
            dataModel = commonViewUtil.currentFiles[0]['dataModel']  
          
        

獲取graphView & dataModel 建議判斷`commonViewUtil.currentFiles`,如果不存在則直接使用全域的 graphView & dataModel

          
            if(commonViewUtil && commonViewUtil.currentFiles){
              commonViewUtil.currentFiles[0]['graphView']
              commonViewUtil.currentFiles[0]['dataModel']
            } else {
              graphView
              dataModel
            }
          
        

Data surce plugin

sourceFormPane 使用一般 html 設計

例如添加連結 a

          
            var href = document.createElement('a');
            href.setAttribute('href', 'http://www.******.com');
            href.innerHTML = 'http://www.*****.com';
            href.style.font = sourceFormPane.getLabelFont();
            href.style.lineHeight = sourceFormPane.getRowHeight() + 'px';
            href.style.textAlign = 'right';
            sourceFormPane.addRow([href], [0.1]);
          
        

dataBindingUI ,使用 input & datalist 做測點下拉篩選功能

          
            var div = document.createElement('div');
            div.id = 'divID';
            var input = document.createElement('input');
            input.type = 'text';
            input.style.font = sourceFormPane.getLabelFont();
            input.style.height = sourceFormPane.getRowHeight() + 'px';
            input.style.lineHeight = sourceFormPane.getRowHeight() + 'px';
            input.id = 'testInput';
            input.setAttribute('list', 'tags');
            input.addEventListener('input', (e) => {
                const userInput = e.target.value;
                console.log(userInput)
                const tagsDatalist = document.getElementById('tags');
                const options = tagsDatalist.querySelectorAll('option');
                options.forEach(option => {
                    if (option.value.indexOf(userInput) === -1) {
                      option.style.display = 'none';
                    } else {
                      option.style.display = 'block';
                    }
                });
            });
            const tags = [
                'dv_tag_01',
                'adam_tag_01',
                'iot_tag_01',
                'wise_tag_01'
            ];
            var datalist = document.createElement('datalist');
            datalist.id = 'tags';
            tags.forEach(city => {
                const option = document.createElement('option');
                option.value = city;
                datalist.appendChild(option);
            });
            div.appendChild(input);
            div.appendChild(datalist);
            sourceFormPane.addRow([{
                element: ''
            }, {element: div, id: 'divID'}], [55, 0.1]);
          
        

applyDataBindingUI 時需要將對應的值讀取返回到 target 物件下存取。

          
            var targets = [];
            target.tags = document.getElementById('testInput').value;
            targets.push(target);
            return targets;
          
        

APM 網路傳輸有資料畫面沒有

SaaS Composer的APM數據源中,默認要求數據要在五分鐘之內, 如果超出五分鐘了就會被認為是無效數據而丟棄處理。 數據時間落後與實際時間有6、7分鐘以上了,數據會被當作無效數據。 可以可以從兩個方面處理此問題
1. 確認網關時間是否落後與實際時間,如果有落後同步一下實際時間就可以, 還有就是邊緣端上傳數據的時間要在五分鐘之內, 超出五分鐘的話後面時間就會被認為是無效數據了
2. 加大數據源五分鐘有效範圍,在SaaS Composer中點擊時間屬性, 根據實際情況設定大一些的範圍,也可解決此問題(如下圖)


設定取樣時間及取樣點

          
            const timeObj = {
              "time": {
                  "from": "now-5m",
                  "to": "now"
              },
              "maxDataPoints": 120
            }
            dataRefreshUtil.timeRange.setTimeRangeToMap(timeObj)
          
        

SaaS Composer的APM數據源中,默認要求數據要在五分鐘之內, 如果超出五分鐘了就會被認為是無效數據而丟棄處理。 數據時間落後與實際時間有6、7分鐘以上了,數據會被當作無效數據。 可以可以從兩個方面處理此問題
1. 確認網關時間是否落後與實際時間,如果有落後同步一下實際時間就可以, 還有就是邊緣端上傳數據的時間要在五分鐘之內, 超出五分鐘的話後面時間就會被認為是無效數據了
2. 加大數據源五分鐘有效範圍,在SaaS Composer中點擊時間屬性, 根據實際情況設定大一些的範圍,也可解決此問題(如下圖)

2D 閃爍

Download

2D 動態換圖


Download

2D 船顯示方向


Download

需要數據源:
一般地圖座標 [“經度, 緯度”, timestamp]
目前寫法是直接修改格式多添加方向 [“經度, 緯度, 方向角度”, timestamp]

開啟場景中加入:

          
            window.LeafIcon = L.Icon.extend({
              options: {
                  // shadowUrl: 'assets/leaf-orange.png?org_id=9',
                  iconSize:     [50, 50],
                  iconAnchor:   [0, 0],
                  popupAnchor:  [-3, -76],
                  degrees: 45
              },
              // PROPERTIES
            x: 66,
            y: 85,
            x_fac: 0.18,
            y_fac: 0.18,
            ctx: null,
            lastHeading: 0,
            lastWindDirection: 0,
              createIcon: function () {
              var s = this.options.iconSize;
                  const canvas = document.createElement('canvas')
                  canvas.width = 100;
                  canvas.height = 100;
                  canvas.style.width = 100 + 'px'
                  canvas.style.height = 100 + 'px'
                  canvas.style.marginLeft = '-25px';
                  canvas.style.marginTop  = '-25px';
                  var ctx = canvas.getContext("2d");
                  ctx.save();
                  ctx.translate(s[0] / 2, s[1] / 2);
                  ctx.rotate(this.options.degrees * Math.PI / 180);
                  ctx.restore();
                  ctx.strokeStyle = '#FF0000'
                  ctx.beginPath();
                  var theta = this.options.degrees * Math.PI / 180
                  var theta120 = 120 * Math.PI / 180
                  var r = Math.min(s[0], s[1]) / 2
                  var dx = r * Math.cos(theta)
                  var dy = r * Math.sin(theta)
                  var dx1 = r * Math.cos(theta - theta120)
                  var dy1 = r * Math.sin(theta - theta120)
                  var dx2 = r * Math.cos(theta + theta120)
                  var dy2 = r * Math.sin(theta + theta120)
                  ctx.moveTo(25 + dx, 25 + dy);
                  ctx.lineTo(25 + dx1, 25 + dy1);
                  ctx.lineTo(25, 25);
                  ctx.lineTo(25 + dx2, 25 + dy2);
                  ctx.closePath();
                  ctx.fill();
                  ctx.stroke();
                  return canvas;
              }
            });
            
            
            window.changeStringtoMapArray = function(strArray){
              var geographicArrays = []
              if (Array.isArray(strArray)){
                strArray.forEach(element => {
                  var arr = element.split(',')
                  geographicArrays.push([arr[1],arr[0],arr[2]])
                  // geographicArrays.push([arr[0],arr[1]])
                });
              }
              return geographicArrays
            }
            
            window.boatMarker = function(leafletMap, markerLayer, data, jsonData, infomation, open){
                var d = changeStringtoMapArray(data);
                var degree = (d[d.length - 1] && d[d.length - 1][2]) ? d[d.length - 1][2] : 0
                var a0 = (d[d.length - 1] && d[d.length - 1][0]) ? d[d.length - 1][0] : 0
                var a1 = (d[d.length - 1] && d[d.length - 1][1]) ? d[d.length - 1][1] : 0
                var greenIcon = new LeafIcon({degrees: degree})
                var marker = L.marker([a0, a1], {icon: greenIcon}).addTo(markerLayer);
                if (infomation){
                    marker.bindPopup(infomation)
                }
                if (open) marker.openPopup();
                return marker;
            }
          
        

2D AR 手機相機互動


Download

2D 錄音撥放


Download

2D 輸入框讀值、改值


Download

2D iframe 鑲入


Download

2D 圖標捲動軸範例


主要是靠圖標 scroll事件進行捲動與重畫 data.iv()

Download

2D 表格與分頁連動


1. 將表格與分頁組件添加至同一個圖標。
2. 將分頁器的total屬性與跟表格的 datasource屬性關聯。
3. 將表格datasource與分頁作關聯
4. 在圖紙上進行數據輸入



Download

2D 表格與分頁連動 2


與外部資料連動
1. 將表格與分頁組件添加至同一個圖標。
2. 在圖紙上, onPostDeserialize 中設定 total總數
3. 在圖紙上, onChange 事件切換表格 datasource

Download

2D 熱點圖


設定熱點半徑、值調整熱點大小

Download

2D 限制整個畫面移動範圍


1. 繪製顯示最大區域範圍
2. 設定顯示區域(如需上下滑動,設定一個比最大區域小的範圍)
3. 添加腳本 GraphView Event,"endPan"
4. 當移動超出設定範圍時,會自動校正。


Download

2D 彈出登入視窗


Download

2D Cesium "3D 地圖圖標整合"


由CesiumJS下載相關檔案,並起Cesium服務。
需要引入 http://localhost:8080/Build/Cesium/Cesium.js (依照前Cesium服務url進行設定)
需要引入 http://localhost:8080/Build/Cesium/Widgets/widgets.css (依照前Cesium服務url進行設定)


需要在 Cesium官網申請AccessToken,並在圖標裡填入 Cesium.Ion.defaultAccessToken = ''

Download

整合Echart第三方擴充套件


說明請參考FAQ.

Download

2D 圖標中使用 ht.ui

主要是在 `renderHTML` 中進行添加

          
            if (!cache.splitLayout) {
              var splitLayout = cache.splitLayout = new ht.ui.SplitLayout();
              splitLayout.setPositionType('absoluteFirst');
              splitLayout.setOrientation('v');
              splitLayout.setPosition(30);
              splitLayout.setSplitterVisible(false);
              splitLayout.setBorder(new ht.ui.border.CSSBorder(1, ht.ui.uiTheme.borderColor));
  
              var table = cache.table = new ht.ui.TableView();
              var tableHeader = new ht.ui.TableHeader(table);
  
              splitLayout.addView(tableHeader, {
                  region: 'first'
              });
              splitLayout.addView(table, {
                  region: 'second'
              });
              table.setScrollBarMode('auto');
  
              var column = new ht.ui.Column();
              column.setName('name');
              column.setDisplayName('Name');
              column.setEditable(true);
              column.setEditorClass('ht.ui.editor.StringEditor');
              table.getColumnModel().add(column);
  
              column = new ht.ui.Column();
              column.setWidth(300);
              column.setDisplayName('Content');
              column.setName('content');
              column.setAccessType('attr');
              table.getColumnModel().add(column);
  
  
              cache.splitLayout.layoutHTML = function () {
                  gv.layoutHTML(data, cache.splitLayout, true);
              };
              splitLayout.getView().addEventListener('mousedown', function (e) {
                  e.stopPropagation();
              })
              splitLayout.beforeCanvas = true;
            }
            if (cache.splitLayout) {
                cache.table.dm().clear()
                // data.a('onload') && data.a('onload')(cache.table)
                if (data.a('tableData') && Array.isArray(data.a('tableData'))) {  // 透過傳入 data 讀取傳入資料將資料填入 table  
                    const sentences = data.a('tableData')
                    for (var i = 0; i < sentences.length; i++) {
                        const sentence = sentences[i];
                        var datacol = new ht.Data();
                        for (let key in sentence){
                            if(key === 'name') {
                                datacol.setName(sentence.name);
                            } else {
                                datacol.a(key, sentence[key]);   
                            }
                        }
                        console.log(datacol)
                        cache.table.dm().add(datacol);
                    }
                }
            }
            return cache.splitLayout; // 將最外層 splitLayout 回傳添加到圖標
          
        

如同一般圖標可以進行數據綁定設定


Download

3D 水管流動

          
            主要是修改貼皮的offset
            1. 使用管線 tag = line
            2. 設定貼皮
            3. 在執行期間:
            if(!window.offset) {window.offset = 0}
            window.offset = window.offset > 0 ? 0 : 0.1
            dataModel.getDataByTag('line').s('shape3d.uv.offset', [window.offset, 0])
          
        

Download


Download

3D 物件改顏色


Download

3D 機器手臂


透過與父代的關聯進行連動

Download

3D 裁切



1. 設定裁切與被裁切的物件
2. 被裁切的物件上可以選擇 Mask ,被那些裁切組影響。
3. 裁切體物件上可設定屬於哪個裁切組、保留外部或內部
4. 記得將裁切體物件設置為不可見。

Download

3D 天空球 (背景圖)


1. 在屬性天空球設定: cube, sphere, color
2. 依設定添入背景或是顏色。
※ 3.3.0以前版本需要額外添加球體作為天空。

Download

3D 動態載入 models


          
            const node = new ht.Node();
            node.s({
                'shape3d': 'models/elevator.json'
            });
            node.p3(0, 0, 0);
            dm.add(node);
          
        
Download

3D 熱點圖


在熱點物件做數據綁定 heatmap 屬性


熱點共同屬性會依照第一組設定生效

Download

3D 導航巡視


使用可參考手冊相關章節

Download

3D 燈光控制


使用可參考手冊相關章節

Download

3D 點雲


本範例在開啟場景添加代碼

          
            const points = new ht.Points();
            dm.add(points);
            pointArray = [];
            for (var i = 0; i < 1660; i++) {
                pointArray.push({
                    x: Math.random() * 3000,
                    y: Math.random() * 3000,
                    e: Math.random() * 3000
                })
            }

            points.s({
                'points.color':"#ff0000",
                'points.image':"circle",
                'points.size':50,
                'shape3d.transmission':false
            })
            points.setPoints(pointArray)
          
        
Download

3D 物理引擎碰撞效果


透過使用 Box2DJS 整合達到物理碰撞效果。
下載檔案後,請先解壓縮,更新開啟場景中 BOX2D.js 的路徑。
BOX2D.js 與ht.js有部分內部行為衝突,建議動態使用範例中動態讀取方式。
請參考HT教學

Download

3D 牆貼上2D或3D場景


此方法可以將 2D或 3D的場景作為貼皮貼到元素表面,需要注意"僅有使用Canvas"繪製的部分可以作為貼皮, 若圖標為DOM生成元素則無法在貼皮上呈現。

Download
          
            let div = document.createElement('DIV'); // 生成承載的 DOM
            div.id = "hiddenDiv";
            div.style.width = "2300px";  // 依場景需求設定大小,會影響貼皮的解析度
            div.style.height = "1375px";
            div.style.position = "relative";
            div.style.visibility = "hidden"; // 隱藏DOM的顯示, 勿使用 display: none
            $('body').append(div);
            let fileName = "displays/builtIn/SpongFactory/SpongFactory.json" // 設定貼皮的圖紙
            var obj = {
                fileName: fileName, 
                gvType: 'displays' // 2D: displays, 3D: scenes
            }
            let option = {
                json: false,
                parentViewId: 'hiddenDiv' // 設定 DOM id
            }
            commonViewUtil.appendDisplayToDOM(obj, option); // 將圖紙貼到 DOM
            
            let canvas = commonViewUtil.getFileObjByFileName(fileName).graphView.getCanvas(); // 獲取 canvas 畫布DOM
            canvas.dynamic = true;
            dm.getDataByTag('screen1').s('right.image', canvas); // 貼皮到指定的 Node 元件上
            setInterval(() => {
              dm.getDataByTag('screen1').iv(); // 刷新节点,图像才会动16.7)
            }, 16.7);
          
        

3D 點擊平面物件添加標示



g3d.intersectObject(event,data)
使用 intersectObject 獲取交點座標,在將交點座標物件中的座標點取出,用於添加新物件
請參考HT教學

Download

3D 點雲 2


Download

3D 文字


  1. 將字體檔轉成 json, 可使用 facetype.js網站進行轉換。
  2. 使用 ht.Default.loadFontFace(url, callback) 載入字型
          
            ht.Default.loadFontFace('assets/Roboto_Regular.json?org_id=36', function() {
              text = new ht.Node();
              text.p3([ -150, 0, 0 ]);
              text.s({
                  'shape3d' : 'text',
                  'shape3d.text' : 'Hello ~'
              });
              dm.add(text);
            });

            // shape3d.text:需要顯示的文本,該屬性被設置則文本最優先使用其。為空時優先使用node的name,再次使用node的label
            // shape3d.text.amount:默認值為0.5,決定文字相對厚度
            // shape3d.text.size:默認值為1,決定文字的放大系數,當然也可以通過(也建議通過)node自身縮放來達成
            // shape3d.text.fill:默認值為true,決定圖形是否實心
            // shape3d.text.curveSegments:默認值為4,決定圖形的曲線采樣頻率,越大越精細(注意性能的平衡)
            // shape3d.text.spacing:默認值為1,決定字之間的間隔大小
            // shape3d.text.font:字體名,注意是json字體文件中的familyName。為空則使用已加載字庫中的第一個
            // shape3d.text.style:默認值為normal,表明字體是normal(標準)、italic(斜體)、oblique(傾斜)
            // shape3d.text.weight:默認值為normal,表明字體是normal(標準)、bold(加粗)
          
        
Download

疊加層遙控面板


Download

疊加層圓形拖拽遙控面板


本範例只提供可拖拽的圖標圖紙,可參考前例改寫

Download

彈窗顯示圖紙


本範例使用 ht.widget.Dialog 彈窗,並在彈窗中顯示圖紙

彈窗可參考 HT 文件,顯示圖紙可參考 FAQ 疊加層說明

Download

Download

Product configuration Sample

可參考本例改寫,修改 UI 上配置


Download

PostgreSQL-plugin(Set value)

可參考本例改寫,修改 UI 上配置

Go to github

influx-v1-plugin(Set value)

可參考本例改寫,修改 UI 上配置

Go to github

Elasticsearch-plugin

可參考本例改寫,修改 UI 上配置

Go to github

csv-data-server

可參考本例改寫,修改 UI 上配置

Go to github

Websocket-plugin

可參考本例改寫,修改 UI 上配置

Go to github

MSSQL-plugin(Set value)

可參考本例改寫,修改 UI 上配置

Go to github

Reference