SVG 夜晚的灯塔案例(use、mask、clipPath ...)

  • 案例效果

    temp.gif

  • 案例代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        html,body {
          margin: 0;
          padding: 0;
          /* 全屏 */
          width: 100%;
          height: 100%;
          /* 清空字号,免得影响 svg */
          line-height: 0;
          font-size: 0;
          /* 天空颜色 */
          background-color: #001122;
        }
      </style>
    </head>
    <body>
      <!-- svg -->
      <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="-400 -300 800 600">
        <!-- 模板 -->
        <defs>
          <!-- 星星 -->
          <polygon id="star" points="0 -10 2 -2 10 0 2 2 0 10 -2 2 -10 0 -2 -2" fill="#fff"/>
        </defs>
        <!-- 真实:天空 + 灯塔 -->
        <g id="real">
          <!-- 星星组 -->
          <g id="star-group"></g>
          <!-- 灯塔 -->
          <g id="light-tower">
            <!-- 模板 -->
            <defs>
              <!-- 灯塔颜色渐变 -->
              <linearGradient id="tower" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0" stop-color="#999"/>
                <stop offset="1" stop-color="#333"/>
              </linearGradient>
              <!-- 灯光颜色渐变 -->
              <radialGradient id="light" cx="0.5" cx="0.5" r="0.5">
                <stop offset="0" stop-color="rgba(255, 255, 255, 0.8)"/>
                <stop offset="1" stop-color="rgba(255, 255, 255, 0)"/>
              </radialGradient>
              <!-- 灯光裁剪范围 -->
              <clipPath id="light-clip">
                <!-- 灯光 -->
                <polygon points="0 0 -400 -15 -400 15" fill="rgba(255, 0, 0, 0.5)"/>
                <!-- 灯点 -->
                <circle cx="0" cy="0" r="2"/>
                <!-- 灯光旋转动画 -->
                <animateTransform attributeName="transform"
                  attributeType="XML"
                  type="rotate"
                  from="0"
                  to="360"
                  dur="10s"
                  repeatCount="indefinite"/>
              </clipPath>
            </defs>
            <!-- 灯塔 -->
            <polygon points="0 0 5 50 -5 50" fill="url(#tower)"/>
            <!-- 灯塔光 -->
            <ellipse cx="0" cy="0" rx="300" ry="100" fill="url(#light)" clip-path="url(#light-clip)"/>
          </g>
          <!-- 月亮 -->
          <g id="moon-group">
            <!-- 月亮蒙板,颜色越亮可见,越黑不可见 -->
            <mask id="moon-mask">
              <circle cx="-300" cy="-150" r="100" fill="white"/>
              <circle cx="-260" cy="-180" r="100" fill="black"/>
            </mask>
            <!-- 月亮形状 -->
            <circle cx="-300" cy="-150" r="100" fill="yellow" mask="url(#moon-mask)"/>
          </g>
        </g>
        <!-- 反射:天空 + 灯塔 -->
        <g id="reflact" mask="url(#fading)">
          <!-- 模板 -->
          <defs>
            <!-- 海面渐变 -->
            <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stop-color="rgba(255, 255, 255, 0.5)"/>
              <stop offset="0.5" stop-color="rgba(255, 255, 255, 0)"/>
            </linearGradient>
            <!-- 海面蒙板,颜色越亮可见,越黑不可见 -->
            <mask id="fading">
              <!-- 海面 -->
              <rect x="-800" y="0" width="1600" height="600" fill="url(#fade)"/>
            </mask>
          </defs>
          <!-- 将 真实 进行反转 -->
          <use xlink:href="#real" transform="scale(1, -1)  translate(0, -100)"/>
        </g>
        <!-- 分割线 -->
        <line x1="-800" y1="50" x2="800" y2="50" stroke="#fff"/>
      </svg>
      <script>
        // 命名空间
        var SVG_NS = 'http://www.w3.org/2000/svg'
        var XLINK_NS = 'http://www.w3.org/1999/xlink'
        // 画布
        var paper = document.querySelector('svg')
        // 渲染星星
        function renderSatr () {
          // 获取星星模板
          var starRef = document.getElementById('star')
          // 获取星星画板
          var starGroup = document.getElementById('star-group')
          // 星星数量
          var starCount = 1000
          // 当前星星
          var star
          while (starCount--) {
            // 通过 use 标签使用星星模板
            star = use(starRef)
            // 星星透明度
            star.setAttribute('opacity', random(0.1, 0.4))
            // 星星摆放位置
            star.setAttribute('transform', `translate(${random(-800, 800)}, ${random(-300, 50)}) scale(${random(0.1, 0.6)})`)
            // 添加到星星画板
            starGroup.append(star)
          }
        }
        // 开始渲染星星
        renderSatr()
        // 创建 use 标签
        function use(origin) {
          var _use = document.createElementNS(SVG_NS, 'use')
          _use.setAttributeNS(XLINK_NS, 'xlink:href', `#${origin.id}`)
          return _use
        }
        // 随机函数
        function random(min, max) {
          return min + (max - min) * Math.random()
        }
      </script>
    </body>
    </html>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡尔特斯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值