1. 程式人生 > >通用儀表盤Dashboard的簡單實踐

通用儀表盤Dashboard的簡單實踐

前言

在這個大資料的時代裡,資料為王,系統能實時展示各種資料顯得尤為重要,所以儀表盤便成為每個系統的標配。

背景

我們都知道大部分前端框架都提供了各種豐富的儀表盤,但有幾點不能滿足我們需求

  1. 不容易隨意拖拽
  2. 不方便動態新增
  3. 無法相容多種前端框架的儀表盤
  4. 不容易統一前端框架
  5. 侷限性多

所以,我們這次採用iframe配合div的方式實現通用儀表盤框架。

選型

我們先找個可拖拽的div,這裡沒有使用h5自帶的拖拽事件,主要懶得二次封裝,比如儀表盤大小、排序等問題。


這裡沒有找到原始碼作者,所以只能提供預覽地址

《jQuery響應式可拖拽的元素元件網格佈局外掛》
以上是大部分功能樣式的效果圖,而且自帶序列化成json檔案,這樣也省去我們改版太多的程式碼。

二次改造

我們大概方案是使用serialization版本,在div中加入iframe,然後控制url,再增加一些拖拽按鈕、放大縮小按鈕,最後增加 新增按鈕,儲存按鈕。

增加urlsrc欄位

我們先改造json檔案

[{"x":0,"y":0,"width":3,"height":4,"src":"demo.html"},{"x":3,"y":0,"width":4,"height":4,"src":"client.html"}]

改造div

this.load_grid = function() {
    this.grid.remove_all();
    var items = GridStackUI.Utils.sort(this.serialized_data);
    _.each(items, function(node, i) {
        this.grid.add_widget($('<div
><div class="grid-stack-item-content"><img class="ui-draggable drog" src="image/move.png" /><iframe class="mainIframe" name="iframe" src="' + node.src + '" width="100%" height="100%" marginwidth="0" marginheight="0" vspace="0" hspace="0" frameborder="0" allowtransparency="true" scrolling="no"
allowfullscreen="true" ></iframe><div id="' + i + '" class="delete">x</div></div><div/>'), node.x, node.y, node.width, node.height); }, this); }.bind(this);

在div中嵌入<iframe class="mainIframe" name="iframe" src="' + node.src + '" width="100%" height="100%" marginwidth="0" marginheight="0" vspace="0" hspace="0" frameborder="0" allowtransparency="true" scrolling="no" allowfullscreen="true" ></iframe>的確有點不美觀,但這裡先簡單這樣寫,後期可以改造。

儲存邏輯

this.save_grid = function() {
        this.serialized_data = _.map($('.grid-stack > .grid-stack-item:visible'), function(el, i) {
            el = $(el);
            var node = el.data('_gridstack_node');
            var src = $(".mainIframe")[i].src;
          var host = window.location.host;
          if(src.indexOf(host)>0){
              src=src.substring(src.indexOf(host)+host.length , src.length);
            }
            return {
                x: node.x,
                y: node.y,
                width: node.width,
                height: node.height,
                src: src
            };
        }, this);
      $.ajax({
          type: "PUT",
          url: "dashboard",
            data:JSON.stringify({"v":JSON.stringify(this.serialized_data)}),
          dataType: "json",
          contentType: "application/json",
          success: function(data) {
              alert("儲存成功");
          },
          error:function (data) {
              alert("儲存失敗");
          },
          complete:function(XMLHttpRequest,textStatus){
          }
      });

    }.bind(this);

控制拖動

$(document).on("mouseover", ".grid-stack-item", function() {
                    $(this).find(".drog").show();
                });
                $(document).on("mouseleave", ".grid-stack-item", function() {
                    $(this).find(".drog").hide();
                });

改變視窗後重繪

    window.onresize = function(obj) {
                $(".mainIframe").each(function(i) {
                    try {
                        $(".mainIframe")[i].contentWindow.resizeWorldMapContainer();
                        $(".mainIframe")[i].contentWindow.myChart.resize();
                    } catch(e) {}
                });
            }

刪除

    $(document).on("click", ".delete", function(el) {
                        el = $(this).closest('.grid-stack-item');
                        self.grid.remove_widget(el);
                    });

拖拽時邏輯

拖拽式 如果不隱藏div,會導致iframe內接受到滑鼠事件,導致無法拖拽,而且頁面改造重繪造成效能損耗較大,所以侵入程式碼,修改了,拖拽邏輯。

        var on_start_moving = function (event, ui) {
            var o = $(this);
            try{
                var controls=document.getElementsByName("iframe");
                for(var i=0;i<controls.length;i++)
                {
                    controls[i].style.visibility="hidden";
                }
            } catch(err){}
            self.grid.clean_nodes();
            self.grid.begin_update(node);
            cell_width = Math.ceil(o.outerWidth() / o.attr('data-gs-width'));
            cell_height = self.opts.cell_height + self.opts.vertical_margin;
            self.placeholder
                .attr('data-gs-x', o.attr('data-gs-x'))
                .attr('data-gs-y', o.attr('data-gs-y'))
                .attr('data-gs-width', o.attr('data-gs-width'))
                .attr('data-gs-height', o.attr('data-gs-height'))
                .show();
            node.el = self.placeholder;

            el.resizable('option', 'minWidth', cell_width * (node.min_width || 1));
            el.resizable('option', 'minHeight', self.opts.cell_height * (node.min_height || 1));
        };

         var on_end_moving = function (event, ui) {
            var o = $(this);
            try{
                var controls=document.getElementsByName("ifame");
                for(var i=0;i<controls.length;i++)
                {
                    controls[i].style.visibility="visible";
                }
            } catch(err){}

            node.el = o;
            self.placeholder.hide();
            o
                .attr('data-gs-x', node.x)
                .attr('data-gs-y', node.y)
                .attr('data-gs-width', node.width)
                .attr('data-gs-height', node.height)
                .removeAttr('style');
            self._update_container_height();
            self.container.trigger('change', [self.grid.get_dirty_nodes()]);

            self.grid.end_update();
        };

主要程式碼

 var controls=document.getElementsByName("iframe");
 for(var i=0;i<controls.length;i++)
 {
     controls[i].style.visibility="hidden";
 }

var controls=document.getElementsByName("iframe");
for(var i=0;i<controls.length;i++)
{
  controls[i].style.visibility="visible";
}              

css樣式

.drog {
    width: 20px;
    height: 20px;
    position: absolute;
    top: 5px;
    left: 5px;
    display: none;
    cursor: pointer;
}

iframe儀表

最後,我們需要準備幾個圖表,這裡可以使用echarts的各種圖表,也可以使用其他任何框架圖表。

由於各個圖表獨立在iframe中,所以互不干擾,這使得我們可以把系統中各個圖表都整合到這個儀表盤中。

總結

該儀表盤設計是一個簡易版的思路,很多程式碼有更好的實現方式,這裡僅提供一種設計思路,不喜勿噴。

記得關注我哦!