前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >波浪动态背景

波浪动态背景

作者头像
itclanCoder
发布2023-09-14 17:21:43
2620
发布2023-09-14 17:21:43
举报
文章被收录于专栏:itclanCoder
代码语言:javascript
复制
const wave = new Wave('#wave', {
  number: 3,
  smooth: 50,
  velocity: 1,
  height: 80,
  colors: [#ff7657],
  opacity: 0.5,
  position: bottom,
  border: {
    show: true,
    width: 2,
    color: [],
  },
})

wave.es.js

代码语言:javascript
复制
function colorHex(color) {
  var that = color;
  //十六进制颜色值的正则表达式
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  // 如果是rgb颜色表示
  if (/^(rgb|RGB)/.test(that)) {
    var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
    var strHex = "#";
    for (var i = 0; i < aColor.length; i++) {
      var hex = Number(aColor[i]).toString(16);
      if (hex.length < 2) {
        hex = '0' + hex;
      }
      strHex += hex;
    }
    if (strHex.length !== 7) {
      strHex = that;
    }
    return strHex;
  }
  else if (reg.test(that)) {
    var aNum = that.replace(/#/, "").split("");
    if (aNum.length === 6) {
      return that;
    }
    else if (aNum.length === 3) {
      var numHex = "#";
      for (var i = 0; i < aNum.length; i += 1) {
        numHex += (aNum[i] + aNum[i]);
      }
      return numHex;
    }
  }
  return that;
}
function colorRgb(color, opacity) {
  var sColor = color.toLowerCase();
  //十六进制颜色值的正则表达式
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  // 如果是16进制颜色
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      var sColorNew = "#";
      for (var i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
      }
      sColor = sColorNew;
    }
    //处理六位的颜色值
    var sColorChange = [];
    for (var i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
    }
    return "rgba(" + sColorChange.join(",") + "," + opacity + ")";
  }
  return sColor;
}

var Wave = /** @class */ (function () {
  function Wave(container, options) {
    var originOption = {
      number: 3,
      smooth: 50,
      velocity: 1,
      height: .3,
      colors: ['#ff7657'],
      border: {
        show: false,
        width: 2,
        color: ['']
      },
      opacity: .5,
      position: 'bottom',
    };
    this.container = document.querySelector(container);
    this.options = Object.assign(originOption, options);
    this.lines = [];
    this.frame = null;
    this.step = 0;
    this.status = 'pause';
    this.init();
    this.draw();
  }
  Wave.prototype.init = function () {
    if (this.container.querySelector('canvas') === null) {
      var canvas = document.createElement('canvas');
      this.container.appendChild(canvas);
    }
    this.canvas = this.container.querySelector('canvas');
    this.canvas.width = this.container.offsetWidth;
    this.canvas.height = this.container.offsetHeight;
    this.ctx = this.canvas.getContext('2d');
    this.setLines();
  };
  Wave.prototype.animate = function () {
    this.status = 'animating';
    this.draw();
  };
  Wave.prototype.pause = function () {
    cancelAnimationFrame(this.frame);
    this.frame = null;
    this.status = 'pause';
  };
  Wave.prototype.setOptions = function (options) {
    this.options = Object.assign(this.options, options);
    this.setLines();
    this.reset();
    if (this.status === 'pause') {
      this.draw();
    }
  };
  Wave.prototype.reset = function () {
    this.init();
  };
  Wave.prototype.draw = function () {
    var _this = this;
    var canvas = this.canvas;
    var ctx = this.ctx;
    var height = this.getWaveHeight();
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    this.step += this.options.velocity;
    this.lines.forEach(function (line, index) {
      var angle = (_this.step + index * 180 / _this.lines.length) * Math.PI / 180;
      var leftHeight = Math.sin(angle) * _this.options.smooth;
      var rightHeight = Math.cos(angle) * _this.options.smooth;
      var vertexs = _this.getVertexs(leftHeight, rightHeight);
      ctx.fillStyle = line.rgba;
      ctx.beginPath();
      ctx.moveTo(vertexs[0][0], vertexs[0][1]);
      if (_this.options.border.show) {
        ctx.lineWidth = _this.options.border.width;
        ctx.strokeStyle = _this.options.border.color[index] ? _this.options.border.color[index] : line.hex;
      }
      if (_this.options.position === 'left' || _this.options.position === 'right') {
        ctx.bezierCurveTo(height + leftHeight - _this.options.smooth, canvas.height / 2, height + rightHeight - _this.options.smooth, canvas.width / 2, vertexs[1][0], vertexs[1][1]);
      }
      else {
        ctx.bezierCurveTo(canvas.width / 2, height + leftHeight - _this.options.smooth, canvas.width / 2, height + rightHeight - _this.options.smooth, vertexs[1][0], vertexs[1][1]);
      }
      if (_this.options.border.show) {
        ctx.stroke();
      }
      ctx.lineTo(vertexs[2][0], vertexs[2][1]);
      ctx.lineTo(vertexs[3][0], vertexs[3][1]);
      ctx.lineTo(vertexs[0][0], vertexs[0][1]);
      ctx.closePath();
      ctx.fill();
    });
    var that = this;
    if (this.status === 'animating') {
      this.frame = requestAnimationFrame(function () {
        that.draw();
      });
    }
  };
  Wave.prototype.setLines = function () {
    this.lines = [];
    for (var i = 0; i < this.options.number; i++) {
      var color = this.options.colors[i % this.options.colors.length];
      var line = {
        hex: colorHex(color),
        rgba: colorRgb(color, this.options.opacity)
      };
      this.lines.push(line);
    }
  };
  Wave.prototype.getVertexs = function (leftHeight, rightHeight) {
    var canvasHeight = this.canvas.height;
    var canvasWidth = this.canvas.width;
    var waveHeight = this.getWaveHeight();
    switch (this.options.position) {
      case 'bottom':
        return [
          [0, waveHeight + leftHeight],
          [canvasWidth, waveHeight + rightHeight],
          [canvasWidth, canvasHeight],
          [0, canvasHeight]
        ];
      case 'top':
        return [
          [0, waveHeight + leftHeight],
          [canvasWidth, waveHeight + rightHeight],
          [canvasWidth, 0],
          [0, 0],
        ];
      case 'left':
        return [
          [waveHeight + leftHeight, 0],
          [waveHeight + rightHeight, canvasHeight],
          [0, canvasHeight],
          [0, 0],
        ];
      case 'right':
        return [
          [waveHeight + leftHeight, 0],
          [waveHeight + rightHeight, canvasHeight],
          [canvasWidth, canvasHeight],
          [canvasWidth, 0],
        ];
    }
  };
  Wave.prototype.getWaveHeight = function () {
    if (this.options.height > 1) {
      switch (this.options.position) {
        case 'bottom':
          return this.canvas.height - this.options.height;
        case 'top':
          return this.options.height;
        case 'left':
          return this.options.height;
        case 'right':
          return this.canvas.width - this.options.height;
      }
    }
    else {
      switch (this.options.position) {
        case 'bottom':
          return this.canvas.height * (1 - this.options.height);
        case 'top':
          return this.canvas.height * this.options.height;
        case 'left':
          return this.canvas.width * this.options.height;
        case 'right':
          return this.canvas.width * (1 - this.options.height);
      }
    }
  };
  return Wave;
}());

export default Wave;

波浪背景组件

代码语言:javascript
复制
<style scoped lang="scss">
  .wave-container {
    .wave {
      height: 400px;
      border: 1px solid #ddd;
    }
    .control {
      .control-item {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        margin-bottom: 15px;
        label {
          font-size: 18px;
          width: 120px;
          flex-shrink: 0;
        }
        .control-value {
          flex-grow: 1;
        }
      }
    }
    .btn-container {
      margin-left: 15px;
    }
    .code-container {
      position: relative;
      min-height: 60px;
    }
    .hide-btn {
      position: absolute;
      right: 15px;
      top: 15px;
    }
  }
</style>

<template>
  <div class="wave-container">
    <div class="wave"></div>
    <div class="code-container">
      <el-button type="primary" size="mini" class="hide-btn"
        @click="hideCode">{{hide?'show':'hide'}} code
      </el-button>
      <div class="language-css extra-class">
           <pre v-show="!hide" class="language-css"><code
             ref="configContainer"></code></pre>
      </div>
    </div>
    <div class="control">
      <div class="control-item">
        <label>toggle</label>
        <el-switch
          v-model="animate"
          active-text="animate"
          inactive-text="pause">
        </el-switch>
      </div>
      <div class="control-item">
        <label>number</label>
        <el-slider class="control-value" :min="0" :max="10"
          v-model="config.number" input-size="mini"
          show-input></el-slider>
      </div>

      <div class="control-item">
        <label>smooth</label>
        <el-slider class="control-value" :min="0" :max="100"
          v-model="config.smooth" input-size="mini"
          show-input></el-slider>
      </div>

      <div class="control-item">
        <label>velocity</label>
        <el-slider class="control-value" :min="1" :max="10"
          v-model="config.velocity" input-size="mini"
          show-input></el-slider>
      </div>
      <div class="control-item">
        <label>height</label>
        <el-slider class="control-value" :min="80"
          :max="300"
          v-model="config.height" input-size="mini"
          :step="10"
          show-input></el-slider>
      </div>
      <div class="control-item">
        <label>colors</label>
        <el-color-picker
          v-for="(color,index) in config.colors"
          :key="index"
          v-model="config.colors[index]"></el-color-picker>

        <div class="btn-container">
          <el-button class="btn"
            v-show="config.colors.length>1"
            @click="delColors(index)" plain size="mini"
            icon="el-icon-minus" circle></el-button>
          <el-button class="btn add-btn" type="primary"
            plain size="mini" icon="el-icon-plus" circle
            @click="addColors"></el-button>
        </div>
      </div>

      <div class="control-item">
        <label>border.show</label>
        <el-switch
          v-model="config.border.show"
        >
        </el-switch>
      </div>
      <div>
        <div class="control-item">
          <label>border.width</label>
          <el-slider class="control-value" :min="1"
            :max="10"
            v-model="config.border.width" input-size="mini"
            show-input></el-slider>
        </div>
        <div class="control-item">
          <label>border.color</label>
          <el-color-picker
            v-for="(color,index) in config.border.color"
            :key="index"
            v-model="config.border.color[index]"></el-color-picker>
          <div class="btn-container">
            <el-button class="btn"
              v-show="config.border.color.length>0"
              @click="delBorderColors(index)" plain
              size="mini" icon="el-icon-minus"
              circle></el-button>
            <el-button class="btn add-btn" type="primary"
              plain size="mini" icon="el-icon-plus" circle
              @click="addBorderColors"></el-button>
          </div>
        </div>
      </div>

      <div class="control-item">
        <label>opacity</label>
        <el-slider class="control-value" :min=".1" :max="1"
          v-model="config.opacity" input-size="mini"
          :step=".1"
          show-input></el-slider>
      </div>

      <div class="control-item">
        <label>position</label>
        <el-radio v-model="config.position"
          label="bottom">bottom
        </el-radio>
        <el-radio v-model="config.position"
          label="top">top
        </el-radio>
        <el-radio v-model="config.position"
          label="left">left
        </el-radio>
        <el-radio v-model="config.position"
          label="right">right
        </el-radio>
      </div>

    </div>

  </div>
</template>

<script>
  import Prism from "prismjs";
  import Wave from './wave.es.js'

  export default {
    name: 'wave',
    data() {
      return {
        animate: true,
        wave: null,
        hide: false,
        config: {
          number: 3,
          smooth: 50,
          velocity: 1,
          height: 80,
          colors: ['#ff7657'],
          opacity: .5,
          position: 'bottom',
          border: {
            show: true,
            width: 2,
            color: [null]
          },
        }
      }
    },
    watch: {
      config: {
        handler() {
          this.wave.setOptions(this.config)
          this.setCode()

        },
        deep: true
      },
      animate() {
        if (this.animate) {
          this.wave.animate()
        } else {
          this.wave.pause()
        }
      }
    },
    methods: {
      hideCode() {
        this.hide = !this.hide
      },
      delColors() {
        this.config.colors.splice(this.config.colors.length - 1)
      },
      addColors() {
        this.config.colors.push('#ff7657')
      },
      delBorderColors() {
        this.config.border.color.splice(this.config.border.color.length - 1)
      },
      addBorderColors() {
        this.config.border.color.push(null)
      },
      setCode() {
        let code = `const wave = new Wave('#wave', {\n${this.getConfigStr(this.config, 1)}})`
        setTimeout(() => {
          this.$refs['configContainer'].innerHTML = Prism.highlight(code, Prism.languages.javascript)
        })
      },
      getConfigStr(obj, index) {
        let config = ''
        let space = ''
        for (let i = 0; i < index * 2; i++) {
          space += ` `
        }
        for (let key in obj) {
          if (Object.prototype.toString.call(obj[key]) === "[object Array]") {
            config += `${space}${key}: [${obj[key].join(', ')}],\n`
          } else if (Object.prototype.toString.call(obj[key]) === "[object Object]") {
            config += `${space}${key}: {\n${this.getConfigStr(obj[key], index + 1)}${space}},\n`
          } else {
            config += `${space}${key}: ${obj[key]},\n`
          }
        }
        return config
      }
    },
    mounted() {
      this.wave = new Wave('.wave', this.config)
      this.wave.animate()
      this.setCode()
    }
  }
</script>
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-19 00:00,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 itclanCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档