HTML+SVG地图标注点动态线条扩散效果的笨方法

Web前端开发 / 22 次阅读

平面地图标注点线条连接效果。常用于公司的子公司或办事处在地图上标注点的效果,线条由总公司的标注点动态发散至各子公司或公事处,实现关联性的效果。

HTML+SVG地图标注点动态线条扩散效果的笨方法

HTML代码:

<section id="global">
    <div class="box" data-aos="fade-up">
        <article class="item">
            <div class="dot"></div>
            <div class="info">
                <!--弹窗信息-->
            </div>
            <div class="svgs">
                <div class="line">
                    <svg viewBox="0 0 147 28">
                        <path d="M1.221,27.592 C1.221,27.592 93.172,-30.117 146.627,24.334 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 11 128">
                        <path d="M7.221,128.592 C7.221,128.592 18.777,28.450 0.711,1.526 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 332 63">
                        <path d="M332.221,63.678 C332.221,63.678 199.326,-23.181 1.262,9.376 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 503 190">
                        <path d="M503.306,190.505 C503.306,190.505 320.289,-69.237 0.899,19.998"/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 794 166">
                        <path d="M794.136,166.850 C794.136,166.850 610.325,-100.723 0.918,46.300 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 735 141">
                        <path d="M736.306,140.592 C736.306,140.592 453.864,-111.599 1.684,62.397 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 667 99">
                        <path d="M667.306,99.678 C667.306,99.678 366.469,-98.539 1.047,70.354 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 758 125">
                        <path d="M759.221,121.678 C759.221,121.678 398.503,-151.382 1.812,126.021 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 592 223">
                        <path d="M593.306,16.592 C593.306,16.592 233.827,-79.580 1.919,224.024 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 597 305">
                        <path d="M598.392,4.505 C598.392,4.505 324.592,-46.590 1.579,306.423 "/>
                    </svg>
                </div>
                <div class="line">
                    <svg viewBox="0 0 267 172">
                        <path d="M268.221,1.592 C268.221,1.592 60.274,7.618 2.369,173.185 "/>
                    </svg>
                </div>
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
        <article class="item">
            <div class="dot"></div>
            <div class="info">
            </div>
        </article>
    </div>
</section>

CSS代码:

/*global*/
html {
    font-size:100px;
}
#global {
    width:14.4rem;
    margin:0 auto;
    .box {
        width: 13rem;
        margin:0.6rem auto 0;
        max-width: 100%;
        background: url(../images/global.svg) no-repeat center center; //global.svg是背景地图,自行准备
        background-size: contain;
        position: relative;
        &:after {
            display: block;
            content: '';
            padding-bottom:(597/1300*100%);
        }
    }
    .dot {
        width: 0.16rem;
        background: url(../images/point_blue.svg) no-repeat center center; //point_blue.svg是蓝色的标注点,自行准备
        background-size: contain;
        &:after {
            display: block;
            content: '';
            padding-bottom:(21/16*100%);
        }
    }
    /*弹窗样式*/
    .info {
        position: absolute;
        left:(-15em/16);
        top:~'calc(100% + 1.0625em)';
        background-color: #fff;
        border-radius: (10em/16);
        padding:(35em/16) (40em/16) (40em/16);
        width:(335em/16);
        box-shadow: 0 (4em/16) (32em/16) rgba(0,51,153,0.12);
        display: none;
        &:before {
            .after;
            left:(20em/16);
            bottom:100%;
            border-bottom: (15em/16) solid #fff;
            border-right: (15em/16) solid transparent;
            border-left: (6em/16) solid transparent;
        }
    }
    /*弹窗样式*/
    .item {
        position: absolute;
        transform: translate(-50%,-50%);
        cursor: pointer;
        z-index: 2;
        &:nth-child(1) {
            left:(977/1300*100%);
            top:(193.5/597*100%);
            .dot {
                background-image: url(../images/point_red.svg);//point_red.svg是色色的标注点,区别总部,自行准备
                width: 0.2rem;
            }
        }
        &:nth-child(2) {
            left:(1123/1300*100%);
            top:(197.5/597*100%);
        }
        &:nth-child(3) {
            left:(646/1300*100%);
            top:(141/597*100%);
        }
        &:nth-child(4) {
            left:(968/1300*100%);
            top:(62.5/597*100%);
        }
        &:nth-child(5) {
            left:(475/1300*100%);
            top:(29/597*100%);
        }
        &:nth-child(6) {
            left:(183/1300*100%);
            top:(82/597*100%);
        }
        &:nth-child(7) {
            left:(243/1300*100%);
            top:(121/597*100%);
        }
        &:nth-child(8) {
            left:(310/1300*100%);
            top:(170/597*100%);
        }
        &:nth-child(9) {
            left:(221/1300*100%);
            top:(205/597*100%);
        }
        &:nth-child(10) {
            left:(386/1300*100%);
            top:(407/597*100%);
        }
        &:nth-child(11) {
            left:(384/1300*100%);
            top:(501/597*100%);
        }
        &:nth-child(12) {
            left:(712/1300*100%);
            top:(370/597*100%);
        }
        &:nth-child(n+10){
            .info {
                top:auto;
                bottom:~'calc(100% + 1.0625em)';
                &:before {
                    bottom:auto;
                    top:100%;
                    border-bottom:none;
                    border-top: (15em/16) solid #fff;
                }
            }
        }
        &.active {
            z-index: 5;
        }
    }
    .svgs {
        svg {
            position: absolute;
            left:0;
            top:0;
            width: 100%;
            height: 100%;
            transition: all 3s;
        }
        path {
            fill: none;
            stroke-width: 0.01rem;
            stroke: var(--main-color);
            stroke-linejoin:miter;
            stroke-linecap:butt;
            fill-rule:evenodd;
        }
        .line {
            position: absolute;
            pointer-events: none;
            &:after {
                display: block;
                content: '';
            }
            &:nth-child(1){
                width: 1.47rem;
                left:(11/20*100%);
                top:(-13/25*100%);
                transform-origin: left center;
                &:after {
                    padding-bottom:(28/147*100%);
                }
                svg {
                    stroke-dasharray:155;
                    stroke-dashoffset:147;
                }
            }
            &:nth-child(2){
                width: 0.11rem;
                bottom:(16/25*100%);
                left:(5/20*100%);
                transform-origin: right bottom;
                &:after {
                    padding-bottom:(128/11*100%);
                }
                svg {
                    stroke-dasharray:128;
                    stroke-dashoffset:128;
                }
            }
            &:nth-child(3){
                width: 3.32rem;
                bottom:(10/25*100%);
                right:(10/20*100%);
                transform-origin: right bottom;
                &:after {
                    padding-bottom:(63/332*100%);
                }
                svg {
                    stroke-dasharray:335;
                    stroke-dashoffset:335;
                }
            }
            &:nth-child(4){
                width: 5.03rem;
                bottom:(14/25*100%);
                right:(5/20*100%);
                transform-origin: 98% bottom;
                &:after {
                    padding-bottom:(190/503*100%);
                }
                svg {
                    stroke-dasharray:575;
                    stroke-dashoffset:575;
                }
            }
            &:nth-child(5){
                width: 7.94rem;
                bottom:(6/25*100%);
                right:(7/20*100%);
                transform-origin: 99% 92%;
                &:after {
                    padding-bottom:(166/794*100%);
                }
                svg {
                    stroke-dasharray:840;
                    stroke-dashoffset:840;
                }
            }
            &:nth-child(6){
                width: 7.35rem;
                bottom:(6/25*100%);
                right:(7/20*100%);
                transform-origin: 99% 92%;
                &:after {
                    padding-bottom:(141/735*100%);
                }
                svg {
                    stroke-dasharray:780;
                    stroke-dashoffset:780;
                }
            }
            &:nth-child(7){
                width: 6.67rem;
                bottom:(6/25*100%);
                right:(7/20*100%);
                transform-origin: 99% 92%;
                &:after {
                    padding-bottom:(99/667*100%);
                }
                svg {
                    stroke-dasharray:690;
                    stroke-dashoffset:690;
                }
            }
            &:nth-child(8){
                width: 7.58rem;
                bottom:(4/25*100%);
                right:(8/20*100%);
                transform-origin: 99% 92%;
                &:after {
                    padding-bottom:(125/758*100%);
                }
                svg {
                    stroke-dasharray:805;
                    stroke-dashoffset:805;
                }
            }
            &:nth-child(9){
                width: 5.92rem;
                top:(4/25*100%);
                right:(8/20*100%);
                transform-origin: 99% 1%;
                &:after {
                    padding-bottom:(223/592*100%);
                }
                svg {
                    stroke-dasharray:665;
                    stroke-dashoffset:665;
                }
            }
            &:nth-child(10){
                width: 5.97rem;
                top:(14/25*100%);
                right:(8/20*100%);
                transform-origin: 98% -1%;
                &:after {
                    padding-bottom:(305/597*100%);
                }
                svg {
                    stroke-dasharray:683;
                    stroke-dashoffset:683;
                }
            }
            &:nth-child(11){
                width: 2.67rem;
                top:(14/25*100%);
                right:(8/20*100%);
                transform-origin: 99% 1%;
                &:after {
                    padding-bottom:(172/267*100%);
                }
                svg {
                    stroke-dasharray:335;
                    stroke-dashoffset:335;
                }
            }
        }
    }
    .current {
        .svgs {
            .line {
                &:nth-child(n+1){
                    svg {
                        stroke-dashoffset:0;
                    }
                }
            }
        }
    }
}
@media only screen and (max-width:1024px) { 
    #global {
        .item {
            &:nth-child(-n+3) {
                .info {
                    left:auto;
                    right: (-15em/16);
                    &:before {                        
                        left:auto;
                        right: (20em/16);
                        border-left-width: (15em/16);
                        border-right-width: (6em/16);
                    }
                }
            }
        }
        .svgs {
            .line {
                transform: scale(0.82);
            }
        }
    }
}
@media only screen and (max-width:750px) { 
    #global {
        .info {
            font-size: 0.14rem;
            padding:1.5em 2em 2em;
        }
        .svgs {
            .line {
                transform: scale(0.35);
            }
        }
    }
}

jQuery代码:

/**/
var $global = $('#global');
var $globalTop = $global.offset().top - $(window).height()/2;
$(window).scroll(function(){
    if($(this).scrollTop() > $globalTop){
        $global.find('.box').addClass('current');
    }else{
        $global.find('.box').removeClass('current');
    }
}).trigger('scroll');

$(window).resize(function(){
    if($(this).width() > 1024){
        $global.find('.item').on('mouseenter mouseleave');
        $global.find('.item').mouseenter(function(){
            $(this).addClass('active').find('.info').stop().fadeIn('fast');
        }).mouseleave(function(){
            $(this).removeClass('active').find('.info').stop().hide();
        });
    }else{
        $global.find('.item').off('mouseenter mouseleave');
        $global.find('.item').off('click').click(function(){
            $(this).toggleClass('active').find('.info').stop().fadeToggle('fast');
            $(this).siblings('.item').removeClass('active').find('.info').hide();
        });
    }
}).trigger('resize');

注:以上代码只适合固定标注点的效果,如果是动态添加的,则不太适合。