HTML5+CSS3实现3D立体雷达动画及源码

  在现如今,随着互联网技术飞速的发展和进步,比如HTML5+CSS3可以做出很炫酷的动画,今天扣丁学堂给大家介绍一下关于一款雷达动画更加让人震撼,它是基于HTML5和CSS3实现,它的一大特点是3D立体的视觉效果,鼠标点击雷达后将会展现一张3D立体地图,并且对地图上指定的几个地点进行坐标详细信息描述。下面我们一起来解析一下这款炫酷的HTML53D雷达动画的实现过程。

HTML5+CSS3实现3D立体雷达动画及源码_第1张图片

  HTML代码

  首先HTML代码非常简单,只需在页面上展示一个div容器即可。

  CSS代码

  这里主要利用了CSS3的旋转等动画特性,看看以下的CSS代码,主要是完成所有的动画:

  @-webkit-keyframesflashing{

  0%,

  30%{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  70%,

  100%{

  -webkit-transform:scale(0);

  transform:scale(0);

  }

  }

  @keyframesflashing{

  0%,

  30%{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  70%,

  100%{

  -webkit-transform:scale(0);

  transform:scale(0);

  }

  }

  @-webkit-keyframespulsation{

  0%{

  -webkit-transform:scale(0);

  transform:scale(0);

  border-color:red;

  background-color:rgba(255,0,0,0.6);

  }

  80%,

  100%{

  -webkit-transform:scale(1);

  transform:scale(1);

  border-color:rgba(255,0,0,0.2);

  background-color:rgba(255,0,0,0.1);

  }

  }

  @keyframespulsation{

  0%{

  -webkit-transform:scale(0);

  transform:scale(0);

  border-color:red;

  background-color:rgba(255,0,0,0.6);

  }

  80%,

  100%{

  -webkit-transform:scale(1);

  transform:scale(1);

  border-color:rgba(255,0,0,0.2);

  background-color:rgba(255,0,0,0.1);

  }

  }

  @-webkit-keyframesrotation{

  from{

  -webkit-transform:rotate(0deg)translateZ(1px);

  transform:rotate(0deg)translateZ(1px);

  }

  to{

  -webkit-transform:rotate(360deg)translateZ(1px);

  transform:rotate(360deg)translateZ(1px);

  }

  }

  @keyframesrotation{

  from{

  -webkit-transform:rotate(0deg)translateZ(1px);

  transform:rotate(0deg)translateZ(1px);

  }

  to{

  -webkit-transform:rotate(360deg)translateZ(1px);

  transform:rotate(360deg)translateZ(1px);

  }

  }

  @-webkit-keyframesscale{

  from{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  to{

  -webkit-transform:scale(1.3);

  transform:scale(1.3);

  }

  }

  @keyframesscale{

  from{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  to{

  -webkit-transform:scale(1.3);

  transform:scale(1.3);

  }

  }

  @-webkit-keyframespolish{

  30%,

  100%{

  -webkit-transform:skewX(35deg)translateX(380%);

  transform:skewX(35deg)translateX(380%);

  }

  }

  @keyframespolish{

  30%,

  100%{

  -webkit-transform:skewX(35deg)translateX(380%);

  transform:skewX(35deg)translateX(380%);

  }

  }

  当然这个雷达光是有动画是不行的,还得有漂亮的外观,用以下CSS代码实现:

  .radar{

  height:40em;

  width:48em;

  position:relative;

  cursor:pointer;

  -webkit-perspective:62.5em;

  perspective:62.5em;

  }

  .radar.radar-map-container,

  .radar.risk-points,

  .radar.scanning-circlecanvas{

  left:0;

  top:0;

  position:absolute;

  }

  .radar.radar-map-container,

  .radar.radar-map,

  .radar.scanning-circle,

  .radar.risk-elements-group{

  -webkit-transition:opacity2.5sease-out,-webkit-transform2.5sease-out,-webkit-transform-origin;

  transition:opacity2.5sease-out,-webkit-transform2.5sease-out,-webkit-transform-origin;

  transition:transform2.5sease-out,opacity2.5sease-out,transform-origin;

  transition:transform2.5sease-out,opacity2.5sease-out,transform-origin,-webkit-transform2.5sease-out,-webkit-transform-origin;

  }

  .radar.radar-map-container,

  .radar.radar-map,

  .radar.scanning-circle{

  will-change:transform;

  }

  .radar.radar-map-container{

  width:400%;

  height:400%;

  left:-150%;

  top:-150%;

  -webkit-transform:scale(0.25);

  transform:scale(0.25);

  -webkit-transform-style:preserve-3d;

  transform-style:preserve-3d;

  }

  .radar.radar-map{

  color:rgba(19,182,206,0.4);

  background:url('http://i64.tinypic.com/5l17ut.jpg')center/containno-repeat;

  width:100%;

  height:100%;

  -webkit-transform-style:preserve-3d;

  transform-style:preserve-3d;

  }

  .radar.radar-map.roaming{

  -webkit-transition-duration:5s!important;

  transition-duration:5s!important;

  -webkit-transition-timing-function:ease-in-out;

  transition-timing-function:ease-in-out;

  -webkit-transition-delay:.5s;

  transition-delay:.5s;

  }

  .radar.radar-map.risk-elements-group{

  opacity:0;

  -webkit-transform-style:preserve-3d;

  transform-style:preserve-3d;

  }

  .radar.radar-map.risk-elements-group.red-flag,

  .radar.radar-map.risk-elements-group.info-panel,

  .radar.radar-map.risk-elements-group.dashed-circle{

  position:absolute;

  }

  .radar.radar-map.risk-elements-group.red-flag,

  .radar.radar-map.risk-elements-group.dashed-circle{

  visibility:hidden;

  }

  .radar.radar-map.risk-elements-group.red-flag,

  .radar.radar-map.risk-elements-group.info-panel{

  -webkit-transform-origin:bottom;

  transform-origin:bottom;

  -webkit-transform:rotateX(-70deg);

  transform:rotateX(-70deg);

  }

  .radar.radar-map.risk-elements-group.red-flag{

  width:0.5em;

  height:10em;

  background-color:white;

  -webkit-transform:rotateX(-70deg)rotateZ(-90deg);

  transform:rotateX(-70deg)rotateZ(-90deg);

  }

  .radar.radar-map.risk-elements-group.red-flag.stand-up{

  -webkit-transform:rotateX(-70deg);

  transform:rotateX(-70deg);

  visibility:visible;

  }

  .radar.radar-map.risk-elements-group.red-flag:before{

  content:attr(data-city);

  font-weight:bold;

  color:white;

  position:absolute;

  background-color:red;

  -webkit-clip-path:polygon(00,100%50%,0100%);

  -moz-clip-path:polygon(00,100%50%,0100%);

  clip-path:polygon(00,100%50%,0100%);

  width:4.782608695652174em;

  height:3.4782608695652173em;

  line-height:3.4782608695652173em;

  font-size:1.4375em;

  font-family:微软雅黑;

  letter-spacing:0.43478260869565216em;

  padding-left:0.5217391304347826em;

  -webkit-box-sizing:border-box;

  box-sizing:border-box;

  top:0.43478260869565216em;

  white-space:nowrap;

  }

  .radar.radar-map.risk-elements-group.red-flag:after{

  content:'';

  position:absolute;

  width:2.1875em;

  height:0.625em;

  border-radius:50%;

  background-color:inherit;

  top:calc(100%-0.625em);

  left:calc(50%-1.09375em);

  }

  .radar.radar-map.risk-elements-group.info-panel{

  -webkit-transform:rotateX(-70deg)translateY(-30%);

  transform:rotateX(-70deg)translateY(-30%);

  -webkit-filter:opacity(0);

  -moz-filter:opacity(0);

  filter:opacity(0);

  border:0.0625emsolid#DCDA6B;

  border-radius:0.25em;

  background-color:rgba(245,228,158,0.31);

  display:table;

  font-weight:bold;

  font-size:2.5em;

  text-shadow:0.025em0.025em0.05emblack;

  padding:0.2em0.3em;

  font-family:黑体;

  overflow:hidden;

  }

  .radar.radar-map.risk-elements-group.info-panel.showup{

  -webkit-filter:opacity(1);

  -moz-filter:opacity(1);

  filter:opacity(1);

  transition:-webkit-filter1slinear0.5s,-moz-filter1slinear0.5s,filter1slinear0.5s,opacity0.5slinear;

  }

  .radar.radar-map.risk-elements-group.info-panel.polish:after{

  -webkit-animation:polish5slinear11s;

  animation:polish5slinear11s;

  }

  .radar.radar-map.risk-elements-group.info-panel.info-title{

  background-image:-webkit-gradient(linear,lefttop,righttop,from(rgba(208,209,120,0.6)),to(rgba(223,226,183,0.05)));

  background-image:linear-gradient(toright,rgba(208,209,120,0.6),rgba(223,226,183,0.05));

  color:#FFE401;

  padding:00.275em;

  border-radius:inherit;

  }

  .radar.radar-map.risk-elements-group.info-panel.info-content{

  color:white;

  margin:0.25em;

  line-height:1.3em;

  }

  .radar.radar-map.risk-elements-group.info-panel:after{

  content:'';

  position:absolute;

  width:30%;

  height:100%;

  -webkit-transform:skewX(35deg)translateX(-160%);

  transform:skewX(35deg)translateX(-160%);

  top:0;

  background-image:-webkit-gradient(linear,lefttop,righttop,from(transparent),color-stop(rgba(255,255,255,0.3)),to(transparent));

  background-image:linear-gradient(toright,transparent,rgba(255,255,255,0.3),transparent);

  }

  .radar.radar-map.risk-elements-group.dashed-circle{

  width:7.5em;

  height:7.5em;

  border-radius:50%;

  background:center/containno-repeat;

  -webkit-animation:rotation5slinearinfinite;

  animation:rotation5slinearinfinite;

  -webkit-transition-property:visibility;

  transition-property:visibility;

  }

  .radar.radar-map.risk-elements-group.dashed-circle:after{

  content:'';

  border-radius:inherit;

  margin:auto;

  width:15%;

  height:15%;

  background-color:#E03636;

  -webkit-box-shadow:000.9375emblack;

  box-shadow:000.9375emblack;

  -webkit-animation:scale1slinearinfinitealternate;

  animation:scale1slinearinfinitealternate;

  position:absolute;

  left:0;

  right:0;

  top:0;

  bottom:0;

  }

  .radar.changing-number-container{

  position:absolute;

  right:12%;

  top:10%;

  bottom:0;

  margin:auto;

  }

  .radar.changing-number-container{

  display:table;

  color:#10ABE0;

  }

  .radar.changing-number-container:before,

  .radar.changing-number-container:after{

  display:inline-block;

  }

  .radar.changing-number-container:before{

  content:'';

  background:-webkit-gradient(linear,lefttop,leftbottom,color-stop(45%,transparent),color-stop(55%,currentColor),color-stop(55%,transparent))center/100%1em;

  background:linear-gradient(tobottom,transparent45%,currentColor55%,transparent55%)center/100%1em;

  width:1em;

  height:100%;

  margin-right:0.625em;

  }

  .radar.changing-number-container:after{

  font-size:0.75em;

  content:attr(data-number);

  width:1.3333333333333333em;

  line-height:1.3333333333333333em;

  word-break:break-all;

  letter-spacing:1.3333333333333333em;

  vertical-align:top;

  font-weight:bold;

  }

  .radar.risk-points{

  z-index:15;

  }

  .radar.risk-points.risk-point-group.risk-point{

  position:absolute;

  width:0.625em;

  height:0.625em;

  border-radius:50%;

  -webkit-filter:blur(2px);

  }

  .radar.risk-points.risk-point-group.risk-point:after{

  content:'';

  display:block;

  height:100%;

  border-radius:50%;

  will-change:transform;

  -webkit-transform:scale(0);

  transform:scale(0);

  }

  .radar.risk-points.risk-point-group.risk-point.type1:after{

  -webkit-box-shadow:000.3125em0.3125emwhiteinset,000.3125em0.5625emrgba(245,76,128,0.54),002.5625em1.5625emrgba(222,17,17,0.89);

  box-shadow:000.3125em0.3125emwhiteinset,000.3125em0.5625emrgba(245,76,128,0.54),002.5625em1.5625emrgba(222,17,17,0.89);

  }

  .radar.risk-points.risk-point-group.risk-point.type2:after{

  -webkit-box-shadow:000.3125em0.3125emwhiteinset,000.3125em0.5625em#15d8e8,002.5625em1.5625emrgba(44,218,226,0.89);

  box-shadow:000.3125em0.3125emwhiteinset,000.3125em0.5625em#15d8e8,002.5625em1.5625emrgba(44,218,226,0.89);

  }

  .radar.risk-points.risk-point-group.risk-point.critical{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  .radar.risk-points.risk-point-group.risk-point.ordinary{

  -webkit-transform:scale(0.4);

  transform:scale(0.4);

  }

  .radar.risk-points.risk-point-group.risk-point.pulsation{

  color:red;

  -webkit-filter:none;

  width:5em;

  height:5em;

  }

  .radar.risk-points.risk-point-group.risk-point.pulsation.pulse-circle{

  position:absolute;

  width:100%;

  height:100%;

  border-radius:50%;

  -webkit-box-sizing:border-box;

  box-sizing:border-box;

  border:0.1875emsolidcurrentColor;

  -webkit-animation:pulsation3slinear1;

  animation:pulsation3slinear1;

  }

  .radar.risk-points.risk-point-group.risk-point.pulsation.pulse-circle:nth-child(2){

  -webkit-animation-delay:.8s;

  animation-delay:.8s;

  }

  .radar.risk-points.risk-point-group.risk-point.pulsation.pulse-circle:nth-child(3){

  -webkit-animation-delay:1.6s;

  animation-delay:1.6s;

  }

  .radar.risk-points.risk-point-group.risk-point.pulsation:after{

  content:'';

  position:absolute;

  width:15%;

  height:15%;

  border-radius:50%;

  background-color:currentColor;

  left:0;

  right:0;

  top:0;

  bottom:0;

  margin:auto;

  }

  .radar.risk-points.risk-point-group.flashing.risk-point:after{

  -webkit-animation:flashing2slinear1;

  animation:flashing2slinear1;

  }

  .radar.scanning-circle{

  position:relative;

  height:100%;

  }

  .radar.scanning-circle.radar-scanner{

  width:40em;

  height:100%;

  margin:0auto;

  position:relative;

  z-index:10;

  -webkit-transform:rotate(125deg);

  transform:rotate(125deg);

  }

  .radar.scanning-circle.radar-scanner.inner-scanner,

  .radar.scanning-circle.radar-scanner.outer-scanner{

  width:100%;

  height:100%;

  }

  .radar.scanning-circle.radar-scanner.inner-scanner{

  display:none;

  position:absolute;

  -webkit-clip-path:inset(00050%);

  -webkit-filter:blur(30px);

  -webkit-animation:rotation30slinearinfinite;

  animation:rotation30slinearinfinite;

  }

  .radar.scanning-circle.radar-scanner.inner-scanner:after{

  content:'';

  -webkit-clip-path:inset(050%00);

  display:block;

  height:100%;

  background-color:rgba(19,182,206,0.3);

  -webkit-transform:rotate(30deg);

  transform:rotate(30deg);

  border-radius:50%;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner{

  -webkit-clip-path:circle(20emat50%48%);

  -moz-clip-path:circle(20emat50%48%);

  clip-path:circle(20emat50%48%);

  -webkit-box-sizing:border-box;

  box-sizing:border-box;

  border:0solidwhite;

  border-top-width:5px;

  border-radius:50%;

  -webkit-box-shadow:0-0.1875em0.3125em#33C9E8,000.9375emwhite,00.3125em0.5em#38C1D2inset;

  box-shadow:0-0.1875em0.3125em#33C9E8,000.9375emwhite,00.3125em0.5em#38C1D2inset;

  will-change:transform;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container{

  height:100%;

  position:relative;

  overflow:hidden;

  border-radius:50%;

  -webkit-transform:rotate(-35deg);

  transform:rotate(-35deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella,

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.color-sector{

  position:absolute;

  width:100%;

  height:100%;

  left:0;

  top:0;

  border-radius:inherit;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella{

  -webkit-clip-path:inset(0050%50%);

  -moz-clip-path:inset(0050%50%);

  clip-path:inset(0050%50%);

  overflow:hidden;

  -webkit-filter:blur(30px);

  -moz-filter:blur(30px);

  filter:blur(30px);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector{

  -webkit-clip-path:inset(050%00);

  -moz-clip-path:inset(050%00);

  clip-path:inset(050%00);

  background-color:rgba(19,182,206,0.2);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(1){

  -webkit-transform:rotate(60deg);

  transform:rotate(60deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(2){

  -webkit-transform:rotate(54deg);

  transform:rotate(54deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(3){

  -webkit-transform:rotate(48deg);

  transform:rotate(48deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(4){

  -webkit-transform:rotate(42deg);

  transform:rotate(42deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(5){

  -webkit-transform:rotate(36deg);

  transform:rotate(36deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(6){

  -webkit-transform:rotate(30deg);

  transform:rotate(30deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(7){

  -webkit-transform:rotate(24deg);

  transform:rotate(24deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(8){

  -webkit-transform:rotate(18deg);

  transform:rotate(18deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(9){

  -webkit-transform:rotate(12deg);

  transform:rotate(12deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.umbrella.color-sector:nth-child(10){

  -webkit-transform:rotate(6deg);

  transform:rotate(6deg);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration{

  position:relative;

  height:100%;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.thin-border,

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.small-ellipse{

  -webkit-filter:blur(2px);

  margin-left:auto;

  margin-right:auto;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.thin-border{

  width:0.0625em;

  height:50%;

  background-color:rgba(65,191,226,0.5);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.small-ellipse{

  background-color:white;

  border-radius:50%;

  position:absolute;

  left:0;

  right:0;

  -webkit-transform:translateZ(0);

  transform:translateZ(0);

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.small-ellipse:nth-child(2){

  width:0.9375em;

  height:0.1875em;

  top:3%;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.small-ellipse:nth-child(3){

  width:1.375em;

  height:0.25em;

  top:17%;

  }

  .radar.scanning-circle.radar-scanner.outer-scanner.scanner-container.scanner-decoration.small-ellipse:nth-child(4){

  width:1em;

  height:0.125em;

  top:33%;

  opacity:0.3;

  }

  .radar.scanning-circle.scanning-dashed-circle{

  -webkit-animation:rotation2.67slinearinfinite;

  animation:rotation2.67slinearinfinite;

  }

  .radar.scanning-circle.scanning-dashed-empty-circle{

  -webkit-animation:rotation1.67slinearinfinite;

  animation:rotation1.67slinearinfinite;

  }

  .radar.lying-down.radar-map-container,

  .radar.lying-down.radar-map,

  .radar.lying-down.scanning-circle,

  .radar.lying-down.risk-elements-group{

  -webkit-transition-duration:1s;

  transition-duration:1s;

  }

  .radar.lying-down.radar-map-container{

  -webkit-transform:scale(1);

  transform:scale(1);

  }

  .radar.lying-down.radar-map{

  -webkit-transform:translateZ(-125em)rotateX(70deg);

  transform:translateZ(-125em)rotateX(70deg);

  color:transparent;

  }

  .radar.lying-down.radar-map.risk-elements-group{

  opacity:1;

  }

  .radar.lying-down.radar-map.risk-elements-group.info-panel{

  opacity:.4;

  }

  .radar.lying-down.radar-map.risk-elements-group.red-flag{

  -webkit-transition:opacity0.5slinear,visibility,-webkit-transform.3slinear;

  transition:opacity0.5slinear,visibility,-webkit-transform.3slinear;

  transition:transform.3slinear,opacity0.5slinear,visibility;

  transition:transform.3slinear,opacity0.5slinear,visibility,-webkit-transform.3slinear;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(19).red-flag{

  -webkit-transition-delay:5.7s,0s,5.7s;

  transition-delay:5.7s,0s,5.7s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(19).dashed-circle{

  -webkit-transition-delay:5.7s;

  transition-delay:5.7s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(18).red-flag{

  -webkit-transition-delay:5.3999999999999995s,0s,5.3999999999999995s;

  transition-delay:5.3999999999999995s,0s,5.3999999999999995s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(18).dashed-circle{

  -webkit-transition-delay:5.3999999999999995s;

  transition-delay:5.3999999999999995s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(17).red-flag{

  -webkit-transition-delay:5.1s,0s,5.1s;

  transition-delay:5.1s,0s,5.1s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(17).dashed-circle{

  -webkit-transition-delay:5.1s;

  transition-delay:5.1s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(16).red-flag{

  -webkit-transition-delay:4.8s,0s,4.8s;

  transition-delay:4.8s,0s,4.8s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(16).dashed-circle{

  -webkit-transition-delay:4.8s;

  transition-delay:4.8s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(15).red-flag{

  -webkit-transition-delay:4.5s,0s,4.5s;

  transition-delay:4.5s,0s,4.5s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(15).dashed-circle{

  -webkit-transition-delay:4.5s;

  transition-delay:4.5s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(14).red-flag{

  -webkit-transition-delay:4.2s,0s,4.2s;

  transition-delay:4.2s,0s,4.2s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(14).dashed-circle{

  -webkit-transition-delay:4.2s;

  transition-delay:4.2s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(13).red-flag{

  -webkit-transition-delay:3.9s,0s,3.9s;

  transition-delay:3.9s,0s,3.9s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(13).dashed-circle{

  -webkit-transition-delay:3.9s;

  transition-delay:3.9s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(12).red-flag{

  -webkit-transition-delay:3.5999999999999996s,0s,3.5999999999999996s;

  transition-delay:3.5999999999999996s,0s,3.5999999999999996s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(12).dashed-circle{

  -webkit-transition-delay:3.5999999999999996s;

  transition-delay:3.5999999999999996s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(11).red-flag{

  -webkit-transition-delay:3.3s,0s,3.3s;

  transition-delay:3.3s,0s,3.3s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(11).dashed-circle{

  -webkit-transition-delay:3.3s;

  transition-delay:3.3s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(10).red-flag{

  -webkit-transition-delay:3s,0s,3s;

  transition-delay:3s,0s,3s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(10).dashed-circle{

  -webkit-transition-delay:3s;

  transition-delay:3s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(9).red-flag{

  -webkit-transition-delay:2.6999999999999997s,0s,2.6999999999999997s;

  transition-delay:2.6999999999999997s,0s,2.6999999999999997s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(9).dashed-circle{

  -webkit-transition-delay:2.6999999999999997s;

  transition-delay:2.6999999999999997s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(8).red-flag{

  -webkit-transition-delay:2.4s,0s,2.4s;

  transition-delay:2.4s,0s,2.4s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(8).dashed-circle{

  -webkit-transition-delay:2.4s;

  transition-delay:2.4s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(7).red-flag{

  -webkit-transition-delay:2.1s,0s,2.1s;

  transition-delay:2.1s,0s,2.1s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(7).dashed-circle{

  -webkit-transition-delay:2.1s;

  transition-delay:2.1s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(6).red-flag{

  -webkit-transition-delay:1.7999999999999998s,0s,1.7999999999999998s;

  transition-delay:1.7999999999999998s,0s,1.7999999999999998s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(6).dashed-circle{

  -webkit-transition-delay:1.7999999999999998s;

  transition-delay:1.7999999999999998s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(5).red-flag{

  -webkit-transition-delay:1.5s,0s,1.5s;

  transition-delay:1.5s,0s,1.5s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(5).dashed-circle{

  -webkit-transition-delay:1.5s;

  transition-delay:1.5s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(4).red-flag{

  -webkit-transition-delay:1.2s,0s,1.2s;

  transition-delay:1.2s,0s,1.2s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(4).dashed-circle{

  -webkit-transition-delay:1.2s;

  transition-delay:1.2s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(3).red-flag{

  -webkit-transition-delay:0.8999999999999999s,0s,0.8999999999999999s;

  transition-delay:0.8999999999999999s,0s,0.8999999999999999s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(3).dashed-circle{

  -webkit-transition-delay:0.8999999999999999s;

  transition-delay:0.8999999999999999s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(2).red-flag{

  -webkit-transition-delay:0.6s,0s,0.6s;

  transition-delay:0.6s,0s,0.6s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(2).dashed-circle{

  -webkit-transition-delay:0.6s;

  transition-delay:0.6s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(1).red-flag{

  -webkit-transition-delay:0.3s,0s,0.3s;

  transition-delay:0.3s,0s,0.3s;

  }

  .radar.lying-down.radar-map:not(.roaming).risk-elements-group:nth-child(1).dashed-circle{

  -webkit-transition-delay:0.3s;

  transition-delay:0.3s;

  }

  .radar.pause-animation.inner-scanner,

  .radar.pause-animation.scanning-dashed-circle,

  .radar.pause-animation.scanning-dashed-empty-circle{

  -webkit-animation-play-state:paused;

  animation-play-state:paused;

  }

  .radar.pause-animation.changing-number-container{

  display:none;

  }

  .radar.pause-animation.risk-points{

  display:none;

  }

  .radar.pause-animation.scanning-circle{

  -webkit-transform:scale(0);

  transform:scale(0);

  opacity:0;

  }

  html,

  body{

  width:100%;

  height:100%;

  }

  body{

  font-size:0.8em;

  margin:0;

  background-color:black;

  }

  .radar{

  left:0;

  right:0;

  top:0;

  bottom:0;

  margin:auto;

  }

  #radar-switch-btn{

  position:absolute;

  left:0;

  top:0;

  color:white;

  }

  @mediaonlyscreenand(max-device-width:667px)and(-webkit-min-device-pixel-ratio:2){

  .radar{

  overflow:hidden;

  }

  }

  JavaScript代码

  JS代码主要是实现向雷达div容器中注入其他元素以及3D地图中地点标注信息的切换展示,代码如下:

  functionRadar(radarContainer){

  radarContainer.innerHTML='

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  \

  ';

  this._container=radarContainer;

  this._containerWidth=this._container.offsetWidth;

  this._containerHeight=this._container.offsetHeight;

  this._centerX=this._containerWidth/2;

  this._centerY=this._containerHeight/2;

  //跟风险点"蒙版"有关的变量

  this._maskCtx=(function(cw,ch){

  varc=document.createElement('canvas');

  c.width=cw;

  c.height=ch;

  returnc.getContext('2d');

  })(this._containerWidth,this._containerHeight);

  this._maskSectorDegree=60;//雷达扇形所占角度

  this._maskStartDegree=0;//雷达扇形开始扫描的角度

  this._scanSpeed=2;//雷达扫描速度,单位为deg

  this._outerScanner=this._container.querySelector('.outer-scanner');//外层雷达扫描器

  this._riskPointsContainer=this._container.querySelector('.risk-points');

  this._allRiskPointsArr=[];//保存所有风险点的数组,改变雷达扫描速度时要用到这些信息

  this._tmpRiskPointsArr=[];//初始化时保存所有的风险点,雷达扫描过程中会遍历这个数组,并把当前扫描到的风险点从这个数组移动到保存风险点的对象中,雷达扫描玩一遍之后这个数组为空。这样做避免雷达扫描时重复遍历风险点,特别是当有很多风险点的时候

  this._riskPoints={};//以扫描角度为键值保存风险点信息

  this._riskElements=[];//与风险点相关的虚线圆圈、红旗、信息面面和位置信息

  this._curRoamingIndex=0;//当前漫游的风险点索引

  this._radarMap=this._container.querySelector('.radar-map');

  this._roamingDuration=0;//两个风险点之间漫游时长

  this._changingNumberContainer=this._container.querySelector('.changing-number-container');//不断变化的数字

  this._digits_base=Math.pow(10,Math.min(this._changingNumberContainer.dataset.number.length,16));//数字位数,最大为16

  this._mapTranslateZ=(function(container){//相机漫游时拉近的距离

  varfontSize=parseInt(getComputedStyle(container).fontSize);

  return300/16*fontSize;

  })(this._container);

  this._scaleFactor=this._radarMap.offsetWidth/this._containerWidth;//为了使地图拉近之后不失真而放大的倍数

  this._rotateX=70;//地图倒下旋转的角度

  }

  /*外部调用的方法*/

  Radar.prototype.init=function(options){

  /*

  options={

  scanSpeed:2//扫描的速度,单位为deg

  }

  */

  options.scanSpeed&&(this._scanSpeed=parseInt(options.scanSpeed));

  this._createCanvasElements();

  this._drawLineAndCircle();

  this._drawDashedCircle();

  this._drawDashedEmptyCircle();

  this._drawScannerSector();

  this._animate();

  this._initEvent();

  };

  //添加风险点

  Radar.prototype.addRiskPoints=function(points){

  if(!(pointsinstanceofArray)){

  points=[points];

  }

  points.forEach(this._addOneRiskPoint.bind(this));

  };

  //一次设置多个风险点

  Radar.prototype.setRiskPoints=function(points){

  this._removeAllRiskPoints();

  this.addRiskPoints(points);

  };

  //调整雷达扫描速度

  Radar.prototype.changeScanSpeed=function(perTimeDeg){

  perTimeDeg=parseInt(perTimeDeg);

  if(perTimeDeg==this._scanSpeed||360%perTimeDeg!=0){//每次旋转的角度必须是360的约数,否则可能会出现跳过风险点的情况

  return;

  }

  this._riskPoints={};

  this._tmpRiskPointsArr=this._allRiskPointsArr;

  this._scanSpeed=perTimeDeg;

  };

  //雷达状态切换

  Radar.prototype.roamingToggle=function(){

  this._container.classList.toggle('lying-down');

  if(this._isLyingDown()){

  //倒下之后停止动画绘制

  this._pauseAnimation();

  }else{

  this._radarMap.classList.remove('roaming');

  this._radarMap.style.removeProperty('transform');

  }

  };

  Radar.prototype.startRoaming=function(){

  this._container.classList.add('lying-down');

  this._pauseAnimation();

  };

  Radar.prototype.stopRoaming=function(){

  this._container.classList.remove('lying-down');

  this._radarMap.classList.remove('roaming');

  this._radarMap.style.removeProperty('transform');

  };

  /*私有方法*/

  Radar.prototype._addOneRiskPoint=function(options){

  /**

  options={

  type:'type1',//'type1'或者'type2',风险点的颜色是红色还是蓝色

  severity:'critical',//风险严重程度,'ordinary'表示普通,'critical'表示严重

  coords:[134.7728099,53.56097399999999],//城市的经纬度

  city:'北京',

  title:'大额预授权交易异常',

  total:3//风险卡的数量

  }

  **/

  //计算风险点屏幕坐标

  varpointCoords=this._geoCoordsToScreenCoords(options.coords),

  point_x=pointCoords[0],

  point_y=pointCoords[1];

  /*//计算风险点索引

  varriskPointIndex=this._calcRiskPointIndex(point_x,point_y);

  if(!this._riskPoints[riskPointIndex]){

  varriskPointGroup=document.createElement('div');//相同索引的风险点放在一组

  riskPointGroup.className='risk-point-group';

  this._riskPointsContainer.appendChild(riskPointGroup);

  this._riskPoints[riskPointIndex]=riskPointGroup;

  }*/

  //创建风险点元素

  varriskPoint=document.createElement('div');

  riskPoint.className='risk-point'+options.type+''+options.severity;

  if(options.type=='pulsation'){

  riskPoint.innerHTML='

  \

  \

  ';

  }

  //this._riskPoints[riskPointIndex].appendChild(riskPoint);

  //计算并设置风险点位置

  varpoint_left=point_x-riskPoint.offsetWidth/2,

  point_top=point_y-riskPoint.offsetHeight/2;

  riskPoint.style.cssText='left:'+point_left+'px;top:'+point_top+'px;';

  varriskPointItem={

  x:point_x,

  y:point_y,

  target:riskPoint

  };

  this._allRiskPointsArr.push(riskPointItem);

  this._tmpRiskPointsArr.push(riskPointItem);

  //创建跟风险点相关的红旗、虚线圆圈和信息面板

  varelements_group=document.createElement('div');

  elements_group.className='risk-elements-group';

  elements_group.innerHTML='

  \

  \

  \

  '+options.title+'

  \

  \

  \

  风险发生地:'+options.city+'\

  \

  \

  风险卡片:'+options.total+'\

  \

  \

  ';

  this._radarMap.appendChild(elements_group);

  vardashed_circle=elements_group.querySelector('.dashed-circle'),

  red_flag=elements_group.querySelector('.red-flag'),

  info_panel=elements_group.querySelector('.info-panel');

  dashed_circle.style.backgroundImage='url('+this._getDashedCircleBg(dashed_circle.offsetWidth)+')';

  //计算和设置圆圈、红旗、信息面板的位置

  vardashed_circle_left=point_x*this._scaleFactor-dashed_circle.offsetWidth/2,

  dashed_circle_top=point_y*this._scaleFactor-dashed_circle.offsetHeight/2,

  red_flag_left=point_x*this._scaleFactor-red_flag.offsetWidth/2,

  red_flag_top=point_y*this._scaleFactor-red_flag.offsetHeight,

  info_panel_left=point_x*this._scaleFactor-info_panel.offsetWidth/2,

  info_panel_top=point_y*this._scaleFactor-info_panel.offsetHeight;

  dashed_circle.style.left=dashed_circle_left+'px';

  dashed_circle.style.top=dashed_circle_top+'px';

  if(this._isLyingDown()){

  dashed_circle.style.visibility='visible';

  }

  red_flag.style.left=red_flag_left+'px';

  red_flag.style.top=red_flag_top+'px';

  info_panel.style.left=info_panel_left+'px';

  info_panel.style.top=info_panel_top+'px';

  //保存与风险点相关的元素

  this._riskElements.push({

  name:options.city,

  riskPoint:riskPoint,

  dashedCircle:dashed_circle,

  redFlag:red_flag,

  infoPanel:info_panel,

  translate:[(this._containerWidth*0.5-point_x)*this._scaleFactor,this._calcTYByTZ(this._mapTranslateZ,dashed_circle.offsetHeight/2)-point_y*this._scaleFactor],

  rotateY:(function(riskElements){

  //旋转的角度正负零交替

  varbase_deg=10,

  max_deviation_deg=5;

  varpn=(riskElements.length%2)*2-1;//positiveornegative

  varnew_base_deg=Math.ceil((riskElements.length+1)%3/2)*base_deg;//1010010100...

  returnpn*(new_base_deg+Math.round(Math.random()*max_deviation_deg));

  })(this._riskElements),

  transformOrigin:Math.round(point_x/this._containerWidth*100)+'%'

  });

  //旋转信息面板,使信息面板转到眼前时正对镜头

  varrotate_deg=this._riskElements[this._riskElements.length-1].rotateY;

  info_panel.style.transform=getComputedStyle(info_panel).transform+'rotateY('+(-rotate_deg)+'deg)';

  };

  //根据名称删除风险点

  Radar.prototype._removeRiskPointByName=function(name){

  for(vari=0,len=this._riskElements.length;i

  varcurRiskElement=this._riskElements[i];

  if(curRiskElement.name==name){

  varriskPointGroup=curRiskElement.riskPoint.parentElement,

  riskElementsGroup=curRiskElement.dashedCircle.parentElement;

  riskPointGroup.removeChild(curRiskElement.riskPoint);

  this._radarMap.removeChild(riskElementsGroup);

  this._riskElements.splice(i,1);

  returntrue;

  }

  }

  returnfalse;

  };

  //删除所有风险点

  Radar.prototype._removeAllRiskPoints=function(){

  vartotal=this._riskElements.length;

  this._radarMap.innerHTML='';

  this._riskPointsContainer.innerHTML='';

  this._riskPoints={};

  this._riskElements=[];

  returntotal;

  };

  //暂停动画

  Radar.prototype._pauseAnimation=function(){

  cancelAnimationFrame(this._requestId);

  this._container.classList.add('pause-animation');

  };

  //恢复动画

  Radar.prototype._resumeAnimation=function(){

  this._requestId=requestAnimationFrame(this._animate.bind(this));

  this._container.classList.remove('pause-animation');

  };

  //创建canvas标签

  Radar.prototype._createCanvasElements=function(){

  varscanningCircleElement=this._container.querySelector('.scanning-circle');

  //绘制雷达静止的线框和圆圈用到的canvas

  varcanvas=document.createElement('canvas');

  canvas.width=this._containerWidth;

  canvas.height=this._containerHeight;

  scanningCircleElement.appendChild(canvas);

  this._lineAndCircleCanvas=canvas;

  //绘制内部旋转的"虚线"圆圈用到的canvas

  this._dashedCircleCanvas=canvas.cloneNode(true);

  this._dashedCircleCanvas.className='scanning-dashed-circle';

  scanningCircleElement.appendChild(this._dashedCircleCanvas);

  //绘制内部旋转的"空心虚线"圆圈用到的canvas

  this._dashedEmptyCircleCanvas=canvas.cloneNode(true);

  this._dashedEmptyCircleCanvas.className='scanning-dashed-empty-circle';

  scanningCircleElement.appendChild(this._dashedEmptyCircleCanvas);

  };

  //地理坐标转换成屏幕坐标

  Radar.prototype._geoCoordsToScreenCoords=function(geoCoords){//geoCoords:经纬度数组

  varchina_geometry_bounds=[73.4994136,53.56097399999999,61.2733963,35.40335839999999];//西北的经纬度和经纬度跨度

  varpoint_x=Math.abs(geoCoords[0]-china_geometry_bounds[0])/china_geometry_bounds[2]*this._containerWidth,

  point_y=Math.abs(geoCoords[1]-china_geometry_bounds[1])/china_geometry_bounds[3]*this._containerHeight;

  return[point_x,point_y];

  };

  //计算风险点的索引(雷达扇形扫描到多少度时要显示这个风险点)

  Radar.prototype._calcRiskPointIndex=function(point_x,point_y){

  varpoint_offset_x=point_x-this._centerX,//与中心点的偏移

  point_offset_y=this._centerY-point_y,

  riskPointRadian=-Math.atan(point_offset_y/point_offset_x);//风险点在雷达扫描圆形的弧度

  if(point_offset_x<0){

  riskPointRadian-=Math.PI;

  }elseif(point_offset_y<0){

  riskPointRadian-=Math.PI*2;

  }

  varriskPointDeg=180/Math.PI*riskPointRadian;

  varriskPointIndex='_deg_'+riskPointDeg.toFixed();

  returnriskPointIndex;

  };

  //根据地图倒下之后translateZ的大小计算风险点应该拉近到相机前面的y值,使得风险点向镜头拉近后正好在屏幕正下方

  Radar.prototype._calcTYByTZ=function(tz,dashed_circle_r){

  varp=parseInt(getComputedStyle(this._container).perspective),//原始视角

  pr=(p-tz)/p,//应用translateZ后的视角比例

  point_screen_bottom_offset=dashed_circle_r/pr,//风险点漫游时要平移到的位置与屏幕底部的偏移量

  tr_o_offset_y=pr*(document.body.clientHeight-this._containerHeight/2-this._container.getBoundingClientRect().top-point_screen_bottom_offset);//最后相机要拉近到的y值与transformorigin中心点的偏移量

  returnthis._radarMap.offsetHeight/2+tr_o_offset_y;

  };

  /*Radar.prototype._calcTYByTZ=function(tz,dashed_circle_r){

  varp=parseInt(getComputedStyle(this._container).perspective),//原始视角

  pr=(p-tz)/p,//应用translateZ后的视角比例

  tmp_tr_o_offset_y=document.body.clientHeight-this._containerHeight/2-this._container.getBoundingClientRect().top;//最后相机要拉近到的y值与transformorigin中心点的偏移量

  vartr_o_offset_y=this._calcOffsetBeforeRotateX(tmp_tr_o_offset_y,this._rotateX,p-tz);

  returnthis._radarMap.offsetHeight/2+tr_o_offset_y*pr;

  };*/

  //根据绕x轴旋转之后风险点的位置计算旋转之前风险点要平移到的位置

  Radar.prototype._calcOffsetBeforeRotateX=function(newOffset,rotateX,oldPerspective){//计算不正确

  //(newOffset/cos(rotateX))/x=oldPerspective/(oldPerspective-x*sin(rotateX))

  varx1=newOffset/Math.cos(Math.PI/180*rotateX);

  returnoldPerspective*x1/(oldPerspective+x1*Math.sin(Math.PI/180*rotateX));

  };

  //动画

  Radar.prototype._animate=function(){

  this._rotateRiskPointMask();

  this._changeNumber();

  this._requestId=requestAnimationFrame(arguments.callee.bind(this));

  };

  //变化数字

  Radar.prototype._changeNumber=function(){

  var_assist_number=arguments.callee._assist_number||0;

  if(_assist_number%6==0){

  varnumber=Math.round(Math.random()*this._digits_base);

  this._changingNumberContainer.dataset.number=number;

  }

  arguments.callee._assist_number=(++_assist_number)%360;

  };

  //绘制雷达静止的线框和圆圈

  Radar.prototype._drawLineAndCircle=function(){

  varradius=this._containerHeight/2,

  ctx=this._lineAndCircleCanvas.getContext('2d');

  //最外层圆圈

  varlineWidth=5;

  ctx.lineWidth=lineWidth;

  ctx.strokeStyle='#0146C2';

  ctx.beginPath();

  ctx.arc(this._centerX,this._centerY,radius-lineWidth/2,0,Math.PI*2);

  ctx.closePath();

  ctx.stroke();

  //内部圆圈

  ctx.fillStyle='rgba(30,199,230,.5)';

  ctx.beginPath();

  ctx.arc(this._centerX,this._centerY,3,0,Math.PI*2);

  ctx.closePath();

  ctx.fill();

  vartotalCircle=8;

  ctx.lineWidth=0.5;

  ctx.strokeStyle='rgba(30,199,230,.5)';

  for(vari=0;i

  ctx.beginPath();

  ctx.arc(this._centerX,this._centerY,radius/totalCircle*(i+1),0,Math.PI*2);

  ctx.closePath();

  ctx.stroke();

  }

  //内部直线

  vartotalLines=14;

  ctx.save();

  ctx.lineWidth=0.3;

  ctx.translate(this._centerX,this._centerY);

  ctx.rotate(Math.PI/totalLines);

  for(vari=0;i

  ctx.rotate(Math.PI*2/totalLines);

  ctx.beginPath();

  ctx.moveTo(0,0);

  ctx.lineTo(0,-radius+lineWidth);

  ctx.closePath();

  ctx.stroke();

  }

  ctx.restore();

  //内部虚线

  ctx.save();

  ctx.setLineDash([2,8]);

  ctx.translate(this._centerX,this._centerY);

  for(vari=0;i

  ctx.rotate(Math.PI*4/totalLines);

  ctx.beginPath();

  ctx.moveTo(0,0);

  ctx.lineTo(0,-radius+lineWidth);

  ctx.closePath();

  ctx.stroke();

  }

  ctx.restore();

  };

  //绘制内部旋转的"虚线"圆圈

  Radar.prototype._drawDashedCircle=function(){

  varctx=this._dashedCircleCanvas.getContext('2d');

  ctx.clearRect(-this._centerX,-this._centerY,this._dashedCircleCanvas.width,this._dashedCircleCanvas.height);

  ctx.globalAlpha=0.8;

  ctx.lineWidth=5;

  ctx.translate(this._centerX,this._centerY);

  varradius=this._containerHeight/2/8*7-ctx.lineWidth/2;

  ctx.strokeStyle='#016FB7';

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/5);

  ctx.stroke();

  ctx.strokeStyle='#23B2D8';

  ctx.rotate(Math.PI/3);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/6);

  ctx.stroke();

  ctx.strokeStyle='#80DEF9';

  ctx.rotate(Math.PI/3);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/18);

  ctx.stroke();

  ctx.strokeStyle='#085BAF';

  ctx.rotate(Math.PI/4);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/9);

  ctx.stroke();

  };

  //绘制内部旋转的空心虚线圆圈

  Radar.prototype._drawDashedEmptyCircle=function(){

  varctx=this._dashedEmptyCircleCanvas.getContext('2d');

  ctx.clearRect(-this._centerX,-this._centerY,this._dashedEmptyCircleCanvas.width,this._dashedEmptyCircleCanvas.height);

  ctx.strokeStyle='#5298D3';

  ctx.globalAlpha=0.3;

  ctx.translate(this._centerX,this._centerY);

  varradius=this._containerHeight/2/8*6,

  radiusDeviation=5,//空心虚线的高度

  innerRadius=radius-radiusDeviation;

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/5);

  ctx.arc(0,0,innerRadius,Math.PI/5,0,true);

  ctx.closePath();

  ctx.stroke();

  ctx.rotate(Math.PI/3);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/6);

  ctx.arc(0,0,innerRadius,Math.PI/6,0,true);

  ctx.closePath();

  ctx.stroke();

  ctx.rotate(Math.PI/3);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/18);

  ctx.arc(0,0,innerRadius,Math.PI/18,0,true);

  ctx.closePath();

  ctx.stroke();

  ctx.rotate(Math.PI/4);

  ctx.beginPath();

  ctx.arc(0,0,radius,0,Math.PI/9);

  ctx.arc(0,0,innerRadius,Math.PI/9,0,true);

  ctx.closePath();

  ctx.stroke();

  };

  //绘制雷达扫描锥形渐变扇形

  Radar.prototype._drawScannerSector=function(){

  //创建canvas元素

  varc=document.createElement('canvas');

  c.width=c.height=this._containerHeight;

  this._outerScanner.querySelector('.umbrella').appendChild(c);

  //绘制锥形渐变

  varctx=c.getContext('2d');

  varsectorCnt=10;//用10块扇形模拟锥形渐变

  varstartDeg=-90,endDeg;

  varsectorRadius=this._containerHeight/2;

  ctx.translate(sectorRadius,sectorRadius);

  ctx.fillStyle='rgba(19,182,206,0.2)';

  for(vari=0;i

  endDeg=startDeg+this._maskSectorDegree-this._maskSectorDegree/sectorCnt*i;

  ctx.beginPath();

  ctx.moveTo(0,0);

  ctx.lineTo(0,sectorRadius);

  ctx.arc(0,0,sectorRadius,Math.PI/180*(startDeg-180),Math.PI/180*endDeg);

  ctx.closePath();

  ctx.fill();

  }

  };

  //旋转只显示风险点的区域

  Radar.prototype._rotateRiskPointMask=function(){

  functionangleToRadian(angle){

  returnMath.PI/180*angle;

  }

  this._maskStartDegree=this._maskStartDegree%360;

  this._maskCtx.beginPath();

  this._maskCtx.moveTo(this._centerX,this._centerY);

  this._maskCtx.arc(this._centerX,this._centerY,this._containerHeight/2,angleToRadian(this._maskStartDegree),angleToRadian(this._maskStartDegree+this._maskSectorDegree));

  this._maskCtx.lineTo(this._centerX,this._centerY);

  this._maskCtx.closePath();

  //控制风险点的显示

  varriskPointIndex='_deg_'+this._maskStartDegree;

  if(!this._riskPoints[riskPointIndex]&&this._tmpRiskPointsArr.length>0){

  //todo:这里先判断this._riskPoints[riskPointIndex]可能会出现不去处理this._tmpRiskPointsArr的情况,特别是当风险点在某一块区域很密集的时候,而且后面添加的风险点都会另开一组

  varthat=this;

  this._tmpRiskPointsArr.forEach(function(point){

  if(that._maskCtx.isPointInPath(point.x,point.y)){

  //把当前扫描到的风险点缓存起来

  if(!that._riskPoints[riskPointIndex]){

  varriskPointGroup=document.createElement('div');//相同索引的风险点放在一组

  riskPointGroup.className='risk-point-group';

  that._riskPointsContainer.appendChild(riskPointGroup);

  that._riskPoints[riskPointIndex]=riskPointGroup;

  }

  that._riskPoints[riskPointIndex].appendChild(point.target);

  point._willDelete=true;//将要删除的标记

  }

  });

  //遍历完之后删除已处理过的风险点

  this._tmpRiskPointsArr=this._tmpRiskPointsArr.filter(function(pointItem){

  varflag=!pointItem._willDelete;

  deletepointItem._willDelete;

  returnflag;

  });

  }

  this._riskPoints[riskPointIndex]&&this._riskPoints[riskPointIndex].classList.add('flashing');

  //旋转雷达扫描扇形

  this._outerScanner.style.transform='rotate('+this._maskStartDegree+'deg)translateZ(0)';

  this._maskStartDegree-=this._scanSpeed;

  };

  //绘制风险点旋转的虚线圆圈背景

  Radar.prototype._getDashedCircleBg=function(radius){

  varcenter_x=radius/2,

  center_y=radius/2;

  varc=document.createElement('canvas');

  c.width=radius;

  c.height=radius;

  varctx=c.getContext('2d');

  ctx.strokeStyle='#EAFF00';

  ctx.shadowColor='#EAFF00';

  ctx.shadowBlur=radius/25;

  //绘制内圆环

  ctx.lineWidth=radius/50;

  ctx.beginPath();

  ctx.arc(center_x,center_y,radius/4,0,Math.PI*2);

  ctx.stroke();

  //绘制外层虚线圆环

  vardash_cnt=5,//实心虚线点个数

  dash_ratio=0.8;//空心虚线点与实心虚线点的比例

  ctx.lineWidth=radius/10;

  varsolid_dash_len=Math.PI*(radius-ctx.lineWidth)/dash_cnt/(1+dash_ratio),

  hollow_dash_len=solid_dash_len*dash_ratio;

  ctx.setLineDash([solid_dash_len,hollow_dash_len]);

  ctx.beginPath();

  ctx.arc(center_x,center_y,radius/2-ctx.lineWidth/2,0,Math.PI*2);

  ctx.stroke();

  returnc.toDataURL();

  };

  //地图倒下之后开始显示风险点处的虚线圆圈、红旗和信息面板

  Radar.prototype._showRiskElements=function(){

  this._riskElements.forEach(function(re,ri){

  re.dashedCircle.style.visibility='visible';

  re.redFlag.classList.add('stand-up');

  });

  };

  //相机漫游到当前风险点时让红旗消失、让信息面板出现

  Radar.prototype._handleCurRiskElements=function(){

  varcurRiskElements=this._riskElements[this._curRoamingIndex];

  if(curRiskElements){

  curRiskElements.redFlag.style.opacity=0;

  curRiskElements.dashedCircle.style.visibility='visible';

  curRiskElements.infoPanel.classList.add('showup');

  curRiskElements.infoPanel.classList.add('polish');

  //设置上一个漫游的风险点的信息面板的透明度

  varlastRiskElements=this._riskElements[(this._curRoamingIndex-1+this._riskElements.length)%this._riskElements.length];

  if(lastRiskElements){

  lastRiskElements.infoPanel.style.removeProperty('opacity');

  }

  }

  };

  //地图回到初始状态时隐藏跟风险点相关的元素

  Radar.prototype._hideRiskElements=function(){

  this._curRoamingIndex=0;

  this._riskElements.forEach(function(re,ri){

  re.redFlag.classList.remove('stand-up');

  re.redFlag.style.opacity=1;

  re.dashedCircle.style.visibility='hidden';

  re.infoPanel.style.removeProperty('opacity');

  re.infoPanel.classList.remove('showup');

  re.infoPanel.classList.remove('polish');

  });

  };

  //风险点镜头漫游

  Radar.prototype._riskPointsRoaming=function(){

  if(!this._isInRoamingState())return;

  varcurRiskElements=this._riskElements[this._curRoamingIndex];

  if(!curRiskElements)return;

  varradarMapStyle='translateZ('+this._mapTranslateZ+'px)rotateY('+curRiskElements.rotateY+'deg)rotateX('+this._rotateX+'deg)translate3d('+curRiskElements.translate[0]+'px,'+curRiskElements.translate[1]+'px,0)';

  //test

  //radarMapStyle='translateZ('+this._mapTranslateZ+'px)translate3d('+curRiskElements.translate[0]+'px,'+curRiskElements.translate[1]+'px,0)';

  //test

  //以上一个风险点为中心绕Y轴旋转(暂时以中心旋转)

  /*varlastRiskElements=this._riskElements[(this._curRoamingIndex-1+this._riskElements.length)%this._riskElements.length];

  this._radarMap.style.transformOrigin=lastRiskElements.transformOrigin;*/

  this._radarMap.style.transform=radarMapStyle;

  curRiskElements.infoPanel.classList.remove('polish');

  //当前的信息面板设置透明度

  varroamingDuration=this._roamingDuration||parseFloat(getComputedStyle(this._radarMap).transitionDuration.split(',')[0]);

  setTimeout(function(that){

  if(that._isLyingDown()){

  curRiskElements.infoPanel.style.opacity=1;

  }

  },roamingDuration*0.5*1000,this);

  };

  //雷达是否是倒下的状态

  Radar.prototype._isLyingDown=function(){

  returnthis._container.classList.contains('lying-down');

  };

  //雷达是否是漫游状态

  Radar.prototype._isInRoamingState=function(){

  returnthis._radarMap.classList.contains('roaming');

  };

  //添加点击事件

  Radar.prototype._initEvent=function(){

  varthat=this;

  this._container.addEventListener('click',function(e){

  that.roamingToggle();

  },false);

  this._riskPointsContainer.addEventListener('animationend',function(e){

  e.target.parentElement.classList.remove('flashing');

  },false);

  this._radarMap.addEventListener('transitionend',function(e){

  if(e.propertyName!='transform')return;

  if(e.target===e.currentTarget){

  if(that._isLyingDown()){

  //地图在倒下的状态

  if(that._isInRoamingState()){

  //相机漫游状态

  that._handleCurRiskElements();//当前风险点漫游结束

  that._curRoamingIndex=(that._curRoamingIndex+1)%that._riskElements.length;

  that._riskPointsRoaming();//下一个风险点漫游开始

  }else{

  //刚刚倒下状态

  that._showRiskElements();

  }

  }else{

  that._hideRiskElements();

  that._resumeAnimation();

  }

  }elseif(e.target.classList.contains('red-flag')&&!e.target.parentElement.nextElementSibling){

  //最后一根红旗树立起来之后开始漫游

  that._radarMap.classList.add('roaming');//修改transitionduration和transitiontiming-function

  setTimeout(function(){

  that._riskPointsRoaming();

  },1000);

  }

  },false);

  };

  varradar=newRadar(document.querySelector('.radar'));

  radar.init({scanSpeed:2});//扫描的速度,单位为deg,必须为360的约数

  radar.addRiskPoints([

  {

  type:'type1',

  severity:'critical',

  coords:[116.407395,39.904211],//北京

  city:'北京',

  title:'大额预授权交易异常',

  total:3

  },{

  type:'type1',

  severity:'ordinary',

  coords:[104.066801,30.572816],//成都

  city:'成都',

  title:'大额预授权交易异常',

  total:3

  },{

  type:'type1',

  severity:'ordinary',

  coords:[121.473701,31.230416],//上海

  city:'上海',

  title:'大额预授权交易异常',

  total:3

  },{

  type:'type2',

  severity:'ordinary',

  coords:[113.264385,23.12911],//广州

  city:'广州',

  title:'大额预授权交易异常',

  total:3

  }

  ]);

  document.querySelector('#radar-switch-btn').addEventListener('click',e=>{

  radar.roamingToggle();

  });

  代码中注释比较详细,有兴趣的同学可以自己进行研究下,HTML5和CSS3真是非常的强大,以上就是关于扣丁学堂HTML5视频教程之HTML5+CSS33D雷达扫描动画的详细介绍,最后想要工作不累就要不断的提升自己的技能,请关注扣丁学堂官网、微信等平台,扣丁学堂IT职业在线学习教育平台为您提供权威的HTML5培训视频教程系统,通过千锋扣丁学堂金牌讲师在线录制的第一套自适应HTML5在线视频课程系统,让你快速掌握HTML5从入门到精通开发实战技能。扣丁学堂H5技术交流群:559883758

你可能感兴趣的:(HTML5+CSS3实现3D立体雷达动画及源码)