可视化项目画布区的前后台布局设计

1,731 阅读2分钟

笔者根据参与可视化项目时探索的经验,对可视化项目前后台布局的要点做了一个梳理,因为最难也是最重要的一个区域就是画布区布局设计,其它区域相对来说要简单一些,所以这次主分享的就是这块区域的布局方案。

后台布局设计

咱们先来看一下后台项目大致的框架图:

后台项目一般都会有个页头,放一些功能或者选项。

然后是左侧组件区,不论是你做可视化页面生成、可视化表单生成还是数据大屏项目,左侧这里存放已添加到画布当中的组件列表是一个很好的选择。

接着是最右侧的配置项区域,可以存放当前选中组件的配置项表单。

最后就是重点:画布区,对于画布区的布局在我刚开始接触可视化项目的时候没有做的很满意,后来经过多次探索才发现了一个比较满意的布局方案。

那接下来我们看一下根据这个方案做的画布区的 demo: 示例地址:kybetter.gitee.io/datascreen-…

其中灰色区域部分可以把它看成是咱们的屏幕(可以假想为手机的屏幕大小)。

灰色区域与背景图片(可以想象为真实的大屏),有一些间距,这是为后台特意加上的,目的是为了方便查看和编辑。

可以看到页头那我放了一个控制条,是用来控制画布缩放的。

最后里面的背景图片,就是真正的画布区了,根据现在 UI 的喜好和目前市面上显示器的显示比例,一般把画布原始大小设置为:1920 * 1080,以对应 16:9 的比例尺。

根据以上描述,方案使用了四层来实现,看代码(我是基于 Vue 做的,其它框架的原理也是一样的):

<!-- 第一层(假想的设备屏幕层),用于限定最大宽度(可以假想为手机的屏幕宽度),
      自身的宽度本示例由 absolute 来设定(当然你也可以用其它方法来设定),
      里面的内容超过自身宽度后,会出现滚动条 -->
<div class="screen-layer">
  <!-- 第二层:用于设定视口的尺寸和位置(可以不要这层),通常会留几十像素的白边,方便观看和操作,
        可以想象为 word 文档周围的空白边),尺寸是根据初始画布的大小来进行缩放计算的 -->
  <div class="viewport-layer" :style="computeViewport">
    <!-- 第三层:缩放控制层,用于对画布尺寸大小进行缩放 -->
    <div class="scale-layer" :style="computeScale">
      <!-- 第四层:画布,尺寸大小为初始设定的画布大小,比如:1920 * 1080 -->
      <div class="canvas-layer" :style="computeCanvas"></div>
    </div>
  </div>
</div>

如果你不需要空白边的话,可以去掉第二层,这样就变为三层了。

各层的 style 需要自己按需计算,很简单,这里给出相关示例代码:

export default {
  data() {
    return {
      scale: 1,
      canvasWidth: 1920,
      canvasHeight: 1080,
    };
  },
  computed: {
    computeScale() {
      return {
        transform: `scale(${this.scale})`,
      };
    },
    computeViewport() {
      return {
        width: Math.round(this.scale * this.canvasWidth + 50) + "px",
        height: Math.round(this.scale * this.canvasHeight + 50) + "px",
      };
    },
    computeCanvas() {
      return {
        width: this.canvasWidth + "px",
        height: this.canvasHeight + "px",
      };
    },
  },
}

最后再贴一下各层的 class:

.screen-layer {
  position: absolute;
  top: 60px;
  left: 100px;
  right: 100px;
  bottom: 30px;
  overflow: auto;
  box-shadow: 0 0 4px 2px #ccc;
  background: url(../assets/bg_m.png) center / 8px 8px;
}
.viewport-layer {
  display: flex;
  justify-content: center;
  align-items: center;
  min-width: 100%;
  min-height: 100%;
}
.scale-layer {
  transition: transform ease 0.15s;
  transform-origin: center center;
  box-shadow: rgba(0, 0, 0, 0.24) 0px 2px 4px 0px;
}
.canvas-layer {
  position: relative;
  background: url(../assets/canvas_bg.jpeg) center / 100% 100% no-repeat;
}

这就是后台画布区的布局方案了。接下来介绍的前端布局方案跟后台类似,只是不需要第二层的白边了。

前台布局设计

前台就很简单了,只需要展示出整个画布就可以了,也就是需要把浏览器铺满,当然这也是要根据你的实际需求来定,本文就按照铺满的来做。

先看一下效果图: 示例地址:kybetter.gitee.io/datascreen-…

话不多说,上代码:

<!-- 第一层:假象的屏幕层 -->
<div class="screen-layer">
  <!-- 第二层:缩放层,用于控制大屏内容的缩放以适应 -->
  <div class="scale-layer" :style="computeScale">
    <!-- 第三层:大屏层,根据真实尺寸来布局 -->
    <div ref="screen-layout" :style="computeSize" class="screen-layout">
    </div>
  </div>
</div>

可以看到与后台画布相比,就少了空白层。

相应的逻辑部分,需要注意的是缩放比例需要根据浏览器窗口大小来计算:

  data() {
    return {
      width: 1920,
      height: 1080,
      scale: "scale(1)",
    };
  },
  computed: {
    computeScale() {
      return {
        transform: this.scale,
      };
    },
    computeSize() {
      return {
        width: this.width + "px",
        height: this.height + "px",
      };
    },
  },
  mounted() {
    this.watchResize();
  },
  methods: {
    /**
     * 监听窗口变化
     */
    watchResize() {
      // 初始加载页面时设置一次缩放比例
      this.calcScale();
      // 当窗口大小有变化时
      window.addEventListener(
        "resize",
        debounce(() => {
          this.calcScale();
        }, 150)
      );
    },

    /**
     * 计算缩放比例
     */
    calcScale() {
      const scale = {
        x: window.innerWidth / this.width,
        y: window.innerHeight / this.height,
      };
      this.scale = `scale(${scale.x}, ${scale.y})`;
    },
  },

相应的画布部分的样式:

/* 屏幕层的大小可以有多种设置方式,这里用 absolute 相对简单,还能自适应浏览器的调整 */
.screen-layer {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
.scale-layer {
  transform-origin: left top;
}
.screen-layout {
  background: url(../assets/canvas_bg.jpeg) center center / 100% 100% no-repeat;
}

完整项目地址

gitee.com/kybetter/da…