zoukankan      html  css  js  c++  java
  • 纯 CSS 实现大量小块儿绘制

    现在做的项目是公司内部全部组要用的 viewer 库. Viewer 需要的功能非常的多,其中的一个就是需要提供一些常用的绘图API功能, 比如用户鼠标移动画箭头,画圈圈,高光选中文本等等。

    挑战

    目前遇到的挑战就是在 canvas, svg, dom + css 之间如何选择的问题,canvas 绘图的方案已经有了成品,我们可以直接拿过来添加到现有的 Viewer 上面。但是基于以下考虑,主要用哪种技术迟迟不能下定论。

    Canvas 纠结点:

    1) 各部门合作问题,如果采用 canvas, 其他部门需要添加自定义图形操作的时候就需要他们了解 Canvas 开发 重绘到 Viewer 已有的 Canvas 上面。 
    2) Canvas 会失去很多 Element 原生的属性,比如文字选中,aria标签, 事件等。
    3) Viewer 的文件可能会非常的大,并且可能会有成千上万个页面,每个页面管理自己的绘图。如果每个页面一个Canvas, 性能会非常差(采用了 View Virtualization 思想,只渲染视图需要的元素,这里是做了个极限假设)。如果所有的图形都绘制在一个Canvas上面,需要根据视图区域的页面属性重绘图形计算,开发成本会增加非常多。 
    4)Canvas 只能用于最底层,否则会覆盖其他元素(Viewer上面的层非常多,需要绘图层能管理事件,同时不丢失其他层的事件)。

    于是老大就给几天时间,让我们尽情地先试着用其他的方式画一下各种图形,比较一下优劣(最后,我们应该会几样技术结合起来用)。其中一个案例就是高光选中文本,后端传会传一堆需要高光块儿大小位置,前端画出高光部分。 像这种非常多小面积的绘图,Canvas是最合适不过的了,不过这几天时间就是看看有没有还有什么其他的方案。大概就长这样,高光是无数个小块儿。

    电脑刺绣绣花厂 http://www.szhdn.com 广州品牌设计公司https://www.houdianzi.com

    寻找方案

    Canvas 画高光的方案已经有了,我们首先想到的就是每一个块儿给个 span 渲染,但因为需要高光的块儿可能会非常多,并且可能会是动态的。哪么这就涉及到 DOM 的频繁操作,性能非常不好。后来采用createDocumentFragment,添加到DOM,性能明显提升。

    我当时有个非常大胆的想法,要是只用一个span,然后所有的块儿都添加成背景可不可以实现(考虑到现在的css3已经有了多背景重叠技术)。找路子的时候千万次觉得不可能,结果实现之后再返回去看,其实原理非常的简单。全部采用css, 用linear-gradient画块儿(采用linear-gradient, 是因为它可以背景重叠,如果有更好的方法欢迎指教),background-position, background-size分别给每个块儿定位,结束!性能当然是惊人的好,因为根本没有涉及到元素的增加删除,只是css重绘(Viewer 有大量消耗性能的scroll监听,操作等情况下都能无缝操作,Canvas 有非常微小地快闪)。这一试,仿佛大概了新世界,很多大量,简单的图形绘制完全可以尝试纯css实现,上代码。

    Angular template

    <span class="layer-content" [style.background]="_background"[style.backgroundSize]="_backgroundSize" [style.backgroundPosition]="_backgroundPosition"></span>

    Angular ts file

        this._subscription = this.highlights$.subscribe((highlights) => {
          let background = ``;
          let backgroundSize = ``;
          let backgroundPosition = ``;
          for (let i = 0; i < highlights.length; i++) {
            const { x, y, width, height } = highlights[i];
            // add connection comma when i is not the last one.
            const comma = (i < highlights.length - 1) ? ', ' : '';
            // 0px transparent to fill gradient syntax.
            background += `linear-gradient(CurrentColor 100%, transparent 0px)${comma}`;
            backgroundSize += `${width}px ${height}px${comma}`;
            backgroundPosition += `${x}px ${y}px${comma}`;
          }
          this._background = this.sanitizer.bypassSecurityTrustStyle(background);
          this._backgroundSize = backgroundSize;
          this._backgroundPosition = backgroundPosition;
        });

    Css

    span.layer-content {
      z-index: 0;
      display: inline-block;
       100%;
      height: 100%;
      background-repeat: no-repeat !important;
    }
  • 相关阅读:
    课程详情页之前台
    课程详情页之后台
    java虚拟机原理图解6--class文件中的字段集合,field字段在class文件中是怎样组织的
    java虚拟机原理图解5--class文件中的访问标志,类索引,父类索引,接口索引集合
    java虚拟机原理图解4--class文件中的常量池详解(下)
    java虚拟机原理图解3--class文件中的常量池详解(上)
    java虚拟机原理图解2--class文件中的常量池
    JVM虚拟机原理图解1--class文件基本组织结构
    Http协议中GET和POST的区别
    SpringCloud插件之ribbon和feign的使用
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/13809153.html
Copyright © 2011-2022 走看看