通用仪表盘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中,所以互不干扰,这使得我们可以把系统中各个图表都整合到这个仪表盘中。

总结

该仪表盘设计是一个简易版的思路,很多代码有更好的实现方式,这里仅提供一种设计思路,不喜勿喷。

猜你喜欢

转载自juejin.im/post/5b568670f265da0f875931e5