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