svg、canvas、css3d实现数据可视化

栏目: Html5 · 发布时间: 5年前

内容简介:这次项目用到了一些自定义的数据可视化组件,我把我做的部分抽出来几个典型做个汇总。分为如下:有些图片(例如下面这个jpg动图)太大,进行了一定程度的压缩,有点模糊(^_^)。

前言:

这次项目用到了一些自定义的数据可视化组件,我把我做的部分抽出来几个典型做个汇总。

分为如下:

  • 星球环绕旋转图 -- 方法一: svg:animateMotion+ animateTransform 方法二:css3d
  • 地图 -- svg渲染 + div悬浮框 + js事件
  • 二维饼图(风车图) -- canvas: dragCircle 、 stopDragging
  • 三棱锥  -- canvas + 对数排列
  • 长方体 -- css3d + 增量增长

星球环绕旋转图

效果展示:

有些图片(例如下面这个jpg动图)太大,进行了一定程度的压缩,有点模糊(^_^)。

svg、canvas、css3d实现数据可视化

我的碎碎念(*^3^):

步骤:

方法一:svg的animateMotion属性 + animateTransform属性

//举例一个星球的动画
<animateMotion dur="6s" begin="0" repeatCount="indefinite">
  <mpath xlinkHref="#Path-12" /> //轨迹动画
</animateMotion>
<animateTransform //自身动画,靠近我的时候星球变大,远离我时变小
  id="first"
  attributeType="XML"
  attributeName="transform"
  type="scale"
  begin="0;second.end "
  from="1"
  to="0.512"
  dur="3s"
  fill="freeze"
/>
<animateTransform
  id="second"
  attributeType="XML"
  attributeName="transform"
  type="scale"
  begin="first.end"
  from="0.512"
  to="1"
  dur="3s"
  fill="freeze"
/>复制代码

方法二:css3d

参考链接: www.jianshu.com/p/2b85973ad…

  • html:
<!-- 轨道 -->
<div class="orbit">
  <!-- 行星 -->
  <div class="planet planet1">
    <!-- <span class="name"></span> -->
  </div>
  <div class="planet planet2">
    <!-- <span class="name"></span> -->
  </div>
</div>复制代码
  • css:
.orbit { //轨道旋转,公转
  border: 5px solid red;
  transform-style: preserve-3d;
  padding: 65px;
  width: 500px;
  height: 500px;
  border-radius: 50%;
  animation: orbit-rotate 10s linear infinite;
}
.planet { //星球自转
  width: 50px;
  height: 50px;
  background: url('../../img/ball1.png') no-repeat;
  background-size: 100% 100%;
  border-radius: 50%;
  animation: self-rotate 10s linear infinite;
}
// (1)rotateX 是为了让整个面倾斜,translateZ是为了防止椭圆(border)因为倾斜发生锯齿,
// (2)停顿效果的产生,其实我是走了野路子的。五个球,根据360/5=72,写了五个不同的关于orbit的class,
// 0 + 72,....360依次增加72,直到360,利用setimeout每隔4秒,按顺序切换一个class
@keyframes orbit-rotate { 
  0% {
    transform: rotateX(70deg) rotateZ(0deg) translateZ(0); 
  }

  100% {
    transform: rotateX(70deg) rotateZ(-360deg) translateZ(0);
  }
}
@keyframes self-rotate {
  0% {
    transform: rotateX(-90deg) rotateY(360deg) rotateZ(0deg);
  }

  100% {
    transform: rotateX(-90deg) rotateY(0deg) rotateZ(0deg);
  }
}
.planet1 { //确定星球开始位置
  position: absolute;
  top: 65px;
  right: 65px;
}

.planet2 { //确定星球开始位置
  position: absolute;
  bottom: 65px;
  right: 65px;
}
复制代码

==/**注意 **/==

参考链接: zh.wikipedia.org/wiki/%E6%A4…

如果为了让星球排列五等分,并且大小根据数值改变星球大小,可以采用以下公式:中心位于点 (h,k)的主轴平行于 x 轴的椭圆由如下方程指定,改变top,left值

svg、canvas、css3d实现数据可视化

svg、canvas、css3d实现数据可视化

♪───O(≧∇≦)O────♪可爱的分割线♪───O(≧∇≦)O────♪

地图

效果展示:

svg、canvas、css3d实现数据可视化

我的碎碎念(*^3^):

步骤:

  • 文件内容

地图文件如下:index.js主文件包含悬浮事件,index.less样式文件,mapStyle.js存放背景地图,pathStyle.js数组格式存放代表地图上小块的路径

svg、canvas、css3d实现数据可视化

svg、canvas、css3d实现数据可视化

  • 渲染地图

代码如下:

svg、canvas、css3d实现数据可视化

根据接口给的数据,按照五个色系分别给不同的path填充(fill)不同的颜色

const colorMap = [
          'rgba(89, 126, 247, 0.8)',
          'rgba(0, 121, 254, 0.8)',
          'rgba(0, 121, 254, 0.8)',
          'rgba(38, 168, 254, 0.8)',
          'rgba(192, 228, 253, 0.8)',
        ];复制代码
  • ​增加悬浮事件

render代码如下:

svg、canvas、css3d实现数据可视化

鼠标移入事件:

svg、canvas、css3d实现数据可视化

鼠标移出事件:

svg、canvas、css3d实现数据可视化

♪───O(≧∇≦)O────♪可爱的分割线♪───O(≧∇≦)O────♪

二维饼图(风车图)

效果展示:

svg、canvas、css3d实现数据可视化

我的碎碎念(*^3^):

步骤:

  • 传入参数
option.push=[{
   color: color[i], //饼图块颜色
   radius: item.revenueTaxAvg, //饼图块半径
   name: item.domainName, // 饼图块名称
   angle: item.companyCnt, //饼图块角度  
}];复制代码
  • 画饼图,PieCanvas.drawPieCanvas('econComposChart', option);

怎么画饼图?,可以参考我以前写的一篇文章: juejin.im/post/5b1e27…

==/* 注意 */==

这篇文章画的是angle一个纬度,只要再增加另外一个纬度radius就好。

canvas画的文字和图,会有一定程度的模糊,解决方案:把画布的宽高增加2倍。

  • 悬浮事件

进行碰撞检测,判断鼠标悬浮是落在哪个弧度的饼图块之间,如果不再饼图块里面悬浮样式消失。 

数学里主要判断逻辑如下:

if(点到圆心的距离<圆的最大半径

&&点到圆心的距离>圆的最小半径

&&点到圆心的直线的角度>扇形的起始角度

&&点到圆心的直线的角度<扇形的结束角度){

点在扇形区域内

}

//使用勾股定理计算这个点与圆心之间的距离   
distanceFromCenter = 
Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2))

//α(弧度)= L (弧长)/ r(半径),但是弧长,我求不出来。
(点到圆心的直线的角度)的范围我主要使用sin(x),如下方法。
判断不同区间的sin(x)值大小,推断出悬浮区域所在的值是什么。复制代码

svg、canvas、css3d实现数据可视化

♪───O(≧∇≦)O────♪可爱的分割线♪───O(≧∇≦)O────♪

三棱锥

效果展示:

svg、canvas、css3d实现数据可视化

步骤:

主要原理:两个三角形 + 一个园 = 三棱锥

svg、canvas、css3d实现数据可视化

canvas.width = canvas.offsetWidth; //防止图片变形
canvas.height = canvas.offsetHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height); 清除画布
 
const { height } = canvas; // 计算等边三角形的高

//如下图,第一个三角形 A-B-C
ctx.moveTo(100, 0); // 从A(100,0)开始
ctx.lineTo(0, height); // 从A(100,0)开始,画到B (0,height)结束
ctx.lineTo(144, height); // B(0,height)-C(144, height)

//第二个三角形 A-C-D
ctx.moveTo(100, 0); // 从A(100,0)开始
ctx.lineTo(143, height); // A-C
ctx.lineTo(210, height); // C-D

//第三个画圆
ctx.arc(100, 23 , 23, 0, Math.PI * 2, false); // 画圆

<canvas id={`pyramid${id}`} height={itemHeight} /> //计算itemHeight复制代码

对数增长--三棱锥高度(itemHeight)计算:

svg、canvas、css3d实现数据可视化

假设输入
 data = [0, 1, 2, 3, 4, 5],x为其中任意值;
 maxHeight 为最大高度;
输出
 itemHeight(0 <= itemHeight< maxHeight),成对数增长

//求最大值
const max = MAX(data)

//排除 x === 0 的情况
因为logmax(max)= 1,且x > 0
由上图可得 0 < logmax(x)< 1
所以 0 < logmax(x) * maxHeight < maxHeight

可知 logmax(x) * maxHeight 成对数变化
又因为logmax(x) = loge(x) / loge(max) 

//写成代码为
const max =data((a, b) => {
  return a > b ? a : b;
}, 0);
itemHeight = x===0 ? 0 : Math.log(x) / Math.log(max) * maxHeight


复制代码

==/* 注意 */== 

y轴计算采用指数增长,因为任意max的0次方 = 1, 所以单独判断 i <= 0的情况

i > 0 ? Math.round(max ** (i * 0.25)) : 0

长方体

效果展示:

svg、canvas、css3d实现数据可视化

步骤:

html

<div id="cube">
        <figure class="front">1</figure>
        <figure class="back">2</figure>
        <figure class="right">3</figure>
        <figure class="left">4</figure>
        <figure class="top">5</figure>
        <figure class="bottom">6</figure>
 </div>复制代码

css

#box.show-front  { transform: translateZ(  -50px ) rotateY(    0deg ); }
#box.show-back   { transform: translateZ(  -50px ) rotateX( -180deg ); }
#box.show-right  { transform: translateZ( -150px ) rotateY(  -90deg ); }
#box.show-left   { transform: translateZ( -150px ) rotateY(   90deg ); }
#box.show-top    { transform: translateZ( -100px ) rotateX(  -90deg ); }
#box.show-bottom { transform: translateZ( -100px ) rotateX(   90deg ); } 复制代码

♪───O(≧∇≦)O────♪可爱的分割线♪───O(≧∇≦)O────♪

总结

我第一次写这么多字的总结技术的文章,排版有点乱,(╯°□°)╯︵ ┻━┻。大部分的内容其实很简单,用到的基本上是初中、高中里面最基础的数学(其实难了,我也不会了_φ(・_・)。

厚着脸皮说,我可能文字功底不咋地,但是每个例子的中心思想应该都表达了。

最后的最后,看在我第一次写了这么多字的份上,给个赞呗(///▽///)。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

你不是个玩意儿

你不是个玩意儿

杰伦·拉尼尔 / 葛仲君 / 中信出版社 / 2011-8 / 35.00元

“你不是个玩意儿。” 这句话当然不是骂人,这是一个宣言。人当然不是玩意儿,不是机器,而是人。 在网络化程度越来越高的今天,我们每个人似乎都有足够的理由,无限欣喜地拥抱互联网。然而,你有没有想过互联网那些不完美的设计却是某种潜在的威胁…… 为什么如此多的暴民在社交网站上争吵不休,很多骂人的脏话我们在现实的人际交往中可能从来不会使用,但在匿名网络环境中却漫天飞舞? 互联网的本质......一起来看看 《你不是个玩意儿》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具