[贝聊科技]「散点图工具包」正式开源

做者:韩永豪 前端开发部 前端开发工程师javascript

背景

以前发布的文章《一个炫酷大屏展现页的打造过程》反响很是热烈,在感谢你们支持的同时,我挑了四个问题,在这里解答一下:前端

  • Q1: 有用到第三方库么?java

  • A1:页面逻辑都是原生写的,简单封装了一些对节点的操做。git

  • Q2:地图是怎么画出来的?github

  • A2:地图是由设计师提供的图片,而地图上闪动的光点和冒出的气泡是DOM节点,样式和动画都是经过CSS实现的。ajax

  • Q3:怎么适配不一样的分辨率?算法

  • A3:适配不一样屏幕尽可能仍是用百分比,至于字体大小或者某些固定大小的元素,这里用到了rem适配,根据屏幕分辨率计算根节点的字体大小,从而调节总体尺寸。npm

  • Q4: 能提供DEMO吗?json

  • A4: 这个问题是你们最感兴趣,也是最多人提出的。因为项目自己涉及到公司机密,所以不方便提供完整的源码,可是通过一番整理,已经把主要的功能独立成一个开源项目。本文的主要内容就是介绍这个开源项目,即 Scatter Map Toolkit」(散点图工具包)浏览器

项目概述

先回顾一下大屏展现页的地图展现模块,其主要功能就是把数据转化为光点显示在地图对应的省份区域内:

预期效果

要实现这个效果,首先碰到的问题就是:地图上的省份是不规则图形,很难界定一个省份的区域,因此本开源项目的第一个功能就是以图形化的界面辅助开发者划定每一个不规则的区域,而且输出为JSON数据。而第二个功能就是根据这份数据把光点定位到具体的区域。

区域划定

按照微积分的原理,要计算一个不规则图形的面积,能够将其切割成若干个矩形,矩形越小,数量越多,覆盖面积越广,矩形面积之和就越接近这个不规则图形的面积,这个工具就是利用这个原理划定区域。

区域切片

要使用这个工具,先从Github克隆本项目到本地,在命令行切换到项目路径,运行:

$ npm install
$ npm start
复制代码

而后用浏览器访问「 http://localhost:8000/ 」便可进入界面,后续操做步骤以下:

  1. 选择图片便可建立新的画布。

初始界面

绘制界面

  1. 以其中一个省份为例,用按下鼠标左键拖动,能够绘制出一个矩形。若是一个矩形不能彻底覆盖该省份,则多画几个。若是有画错的矩形能够把鼠标移至该矩形上方,点击右上角的删除按钮。

绘制矩形

  1. 若是某些省份过小,操做困难,可使用缩放功能。

绘图操做

  1. 绘制完毕后能够为该组重命名,点击右上角的加号还能够继续添加分组。若是有不想要的分组,能够选择整组删除。若是有分组互相遮挡,能够点击隐藏按钮进行隐藏。(与Photoshop中的图层相似)

分组操做

  1. 绘制完毕后,能够下载配置项,把数据保存下来,以便使用或者修改。

配置操做

最终效果以下:

总体效果

生成的JSON文件以下:

{
  "image": "https://qiniu-pic.ibeiliao.com/o_1c93ofmqlug61uid15qe174d5ke7.png",
  "data": {
    "广东": {
      "isShow": true,
      "areas": [
        {
          "x1": "58.778625954198475%",
          "x2": "64.02035623409668%",
          "y1": "71.23695976154993%",
          "y2": "78.09239940387481%"
        },
        {
          "x1": "64.02035623409668%",
          "x2": "70.38167938931298%",
          "y1": "73.91952309985098%",
          "y2": "78.09239940387481%"
        },
        
        ...
        
      ]
    }
  },
  "setting": {
    "resize": true,
    "width": 1310,
    "height": 895
  }
}
复制代码

区域数据使用

生成这份区域数据以后要如何使用呢?首先,一个光点必然是显示在某个省的区域内的,因此要从数据中找到该省份的配置:

// 全部的区域数据都存在这个json文件内
ajax('options.json').then((options) => {
    // 广东省的矩形区域集合
    options.data['广东'].areas;
});

复制代码

其次,在矩形区域集合内随机选择一个区域,并在该区域内随机选择一个点:

// 在区域中随机选取一个坐标点
function radom(area) {
    let x1 = parseFloat(area.x1);
    let x2 = parseFloat(area.x2);
    let y1 = parseFloat(area.y1);
    let y2 = parseFloat(area.y2);
    
    return {
        x: x1 + ((x2 - x1) * Math.random()) + '%',
        y: y1 + ((y2 - y1) * Math.random()) + '%'
    };
}

// 从集合中随机获取一个矩形区域
function getArea(areas) {
    return areas[Math.floor(Math.random() * areas.length)];
}

// 全部的区域数据都存在这个json文件内
ajax('options.json').then((options) => {
    // 随机获取一个矩形区域
    let area = getArea(options.data['广东'].areas);
    
    // 随机获取一个坐标点
    random(area);
});
复制代码

然而,这种作法会出现一个问题:面积大的矩形里面的点被选中的几率和面积小的矩形被选中的几率不一致。假设一个省份包含两个矩形区域:

平均计算

具体的体现就是面积小的矩形里面的点会更密集。为了解决这个问题,咱们对随机选取矩形的算法进行了改良,面积越大被选中的几率就越大。思路很简单,把全部矩形的面积转化成一条线段(200个点+50个点=250个点的线段),在这条线上面随机获取一个点,这个点所在的线段对应的矩形就是随机获取到的矩形,由于矩形A在线段上占比更大,因此获取到点的几率也更大:

面积转化成线段

实现代码以下:

/** 根据每一个矩形的权重,随机获取一个矩形区域
* @param {Array} areas 矩形集合
*   @param {Number} areas[i].sumArea 改矩形的面积
* @param {Number} sumArea 全部矩形的总面积
*/
function getArea(areas, sumArea) {
    let currentSumArea = 0; // 当前累计总面积
    let result = null; // 查找结果
	this.areas.some((area) => {
        // 查找这个数落在哪条线段上
		if (
		    random >= currentSumArea &&
		    random <= currentSumArea + area.sumArea
	    ) {
			result = area;
			return true;
		}
		currentSumArea += area.sumArea;
	});

	return result;
}
复制代码

这样改良后,两个矩形里面的点被选中的几率都是同样的:

权重计算

这里的功能已经封装为项目中「 /dist/scatter-map.min.js 」的randomFromGroup方法

案例

最后回归到一开始说的地图展现模块,如今只须要先用区域划定工具生成区域数据,而后引入库,再调用它的方法,就能够获取随机坐标点。

<scrpit type="text/javascript" src="dist/scatter-map.min.js"></script>

<scrpit type="text/javascript">

ajax('options.json').then((options) => {
    // 工具实例化
    let scatterMap = new ScatterMap(options);

    // 随机获取广东省的一个坐标点,格式以下:
    // { x: '50%', y: '50%' }
    scatterMap.randomFromGroup('广东');
});

</script>

复制代码

而后,只须要根据这个坐标点设置光点的位置,加上样式和动画便可完成上述效果。

总结与展望

  • 虽然项目的总体功能都已经完成,可是因为时间限制,区域划定工具还存在一些兼容性问题,目前建议经过谷歌浏览器打开使用,后续会完善兼容代码。

  • 当前版本的工具包不含光点绘制功能,例子中的光点绘制是经过DOM节点实现的,若是数量过多,有可能会形成页面卡顿,浏览器占用内存过大。所以,接下来会考虑把使用SVG或Canvas实现光点绘制。

  • 当前版本的区域划定功能还不够方便,须要繁琐的手动操做,后续但愿能够作到Photoshop魔法棒的效果,能够根据色差判断不规则区域的覆盖范围,这样绘制的效率将会大大提升。

项目地址

最后再贴一下地址,但愿你们多多支持:github.com/beiliao-mob…

相关文章
相关标签/搜索