<div id="app">
    <!-- 使用 clip-path -->
    <div id="svgpolygon" v-bind:style="styleObject"></div>
    <label>Sides: {{ sides }}</label>
    <input type="range" min="3" max="500" v-model.number="sides">
    <label>Minimum Radius: {{ minRadius }}%</label>
    <input type="range" min="0" max="90" v-model.number="minRadius">
    <label>Update Interval: {{ updateInterval }} milliseconds</label>
    <input type="range" min="10" max="2000" v-model.number="updateInterval">
</div>
#svgpolygon {
    display: block;
    width: 180px;
    height: 180px;
    border-radius: 50%;
    border: 1px solid #333;
}

input[type="range"] {
  display: block;
  width: 100%;
  margin-bottom: 15px;
}
View Compiled
new Vue({
    el: "#app",
    data: function() {
        var defaultSides = 500;
        var stats = Array.apply(null, { length: defaultSides }).map(function() {
            return 100;
        });
        return {
            stats: stats,
            points: generatePoints(stats),
            sides: defaultSides,
            minRadius: 50,
            interval: null,
            updateInterval: 500
        };
    },
    computed: {
        styleObject: function() {
            return {
                background: '#41B883',
                'clip-path': 'polygon(' + this.points +')'
            }
        }
    },
    watch: {
        sides: function(newSides, oldSides) {
            var sidesDifference = newSides - oldSides;
            if (sidesDifference > 0) {
                for (var i = 1; i <= sidesDifference; i++) {
                    this.stats.push(this.newRandomValue());
                }
            } else {
                var absoluteSidesDifference = Math.abs(sidesDifference);
                for (var i = 1; i <= absoluteSidesDifference; i++) {
                    this.stats.shift();
                }
            }
        },
        stats: function(newStats) {
            TweenLite.to(this.$data, this.updateInterval / 1000, {
                points: generatePoints(newStats)
            });
        },
        updateInterval: function() {
            this.resetInterval();
        }
    },
    mounted: function() {
        this.resetInterval();
    },
    methods: {
        randomizeStats: function() {
            var vm = this;
            this.stats = this.stats.map(function() {
                return vm.newRandomValue();
            });
        },
        newRandomValue: function() {
            return Math.ceil(
                this.minRadius + Math.random() * (100 - this.minRadius)
            );
        },
        resetInterval: function() {
            var vm = this;
            clearInterval(this.interval);
            this.randomizeStats();
            this.interval = setInterval(function() {
                vm.randomizeStats();
            }, this.updateInterval);
        }
    }
});

function valueToPoint(value, index, total) {
    var x = 0;
    var y = -value * 0.9;
    var angle = Math.PI * 2 / total * index;
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);
    var tx = x * cos - y * sin + 100;
    var ty = x * sin + y * cos + 100;
    return { x: tx, y: ty };
}

function generatePoints(stats) {
    var total = stats.length;
    var points = stats
        .map(function(stat, index) {
            var point = valueToPoint(stat, index, total);
            return point.x + "px " + point.y +"px,";
        })
        .join(" ");
    
    points = points.slice(0, -1);
     
    return points;
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js