SOURCE

console 命令行工具 X clear

                    
>
console
vm = new Vue({
  el: 'body',
  data: {
    ball: {

      x: 0,
      y: 0,
      z: 0,
      rx: 0,
      ry: 0,
      rz: 0,
      clipwidthheight: 40,
      hanasuR: 0,
      clips: []
    },

  },
  methods: {
    rotateYDeg: function($index, len) {
      if ($index == 0 || $index >= (len - 1)) {
        return (Math.floor($index / (len - 1)) - 90);
      } else {

        return this.lines[$index].y;
      }

    },
    rotateXDeg: function($index) {

      return this.lines[$index].x;
      //					return (Math.floor($index/(36-Math.floor($index/36)))*10);
    }
  },
  computed: {
    ballR: {
      get: function() {

        return Math.sqrt(this.ball.clips.length * this.ball.clipwidthheight * this.ball.clipwidthheight / 4 / Math.PI)

      },
      set: function(newValue) {

}
    },
    lines: {
      get: function() {

        var lineCount = Math.floor(0.5 * Math.PI * this.ballR / this.ball.clipwidthheight);
        var lines = []
        var inx = 0;
        for (var i = 0; i <= lineCount; i++) {
          var count = Math.floor((2 * Math.PI * i / lineCount) * Math.floor(this.ballR / this.ball.clipwidthheight)) + Math.ceil(Math.sin(i / lineCount * Math.PI) * lineCount + 1);

          for (var j = 0; j < count; j++) {
            lines[inx] = {
              x: j * 360 / count,
              y: i / lineCount * 90 - 90
            };
            inx += 1;
          }

        }
        for (var i = 0; i <= (lineCount - 1); i++) {
          var count = Math.floor((2 * Math.PI * i / lineCount) * Math.floor(this.ballR / this.ball.clipwidthheight)) + Math.ceil(Math.sin(i / lineCount * Math.PI) * lineCount + 1);

          for (var j = 0; j < count; j++) {
            lines[inx] = {
              x: j * 360 / count,
              y: i / lineCount * 90 + 90
            };
            inx += 1;
          }

        }
        console.log(lines);
        return lines;

      },
      set: function(newValue) {

}
    }

  }

});

for (var i = 0; i < 500; i++) {
  vm.ball.clips.push({
    hanasu: 0
  })
} (function() {
  var isDrag = false;
  var obj = null;
  var preX = null;
  var preY = null;
  document.addEventListener('mousewheel', function(e) {

    if (e.altKey) {
      vm.ball.rz += e.originalEvent.wheelDelta;

    } else {
      vm.ball.z += e.originalEvent.wheelDelta;
    }
  });
  document.addEventListener('mousedown', function(e) {
    isDrag = true;
    obj = this;
    preX = e.clientX;
    preY = e.clientY;
  });
  document.addEventListener('mouseup', function(e) {
    isDrag = false;
    preX = null;
    preY = null;
    obj = null;

  });
  document.addEventListener('mousemove', function(e) {

    if (isDrag && obj) {

      if (e.altKey) {
        vm.ball.ry += (e.clientX - preX) / 10;

        vm.ball.rx -= (e.clientY - preY) / 10;

        preX = e.clientX;
        preY = e.clientY;
      } else {
        vm.ball.x += (e.clientX - preX);

        vm.ball.y += (e.clientY - preY);

        preX = e.clientX;
        preY = e.clientY;
      }
    }

  });
})();
<div id="canvas" style="position: relative;width: 600px;height: 600px;overflow: hidden;">
  <div class="object3d" v-bind:style="{transform:'translate3d('+ball.x+'px,'+ball.y+'px,'+ball.z+'px) rotateX('+ball.rx+'deg) rotateY('+ball.ry+'deg) rotateZ('+ball.rz+'deg)'}">
    <div class="clip" v-for="b in ball.clips" v-on:mouseover="b.hanasu+=10;"
    v-on:mouseout="b.hanasu-=10;" v-if="lines[$index]" style="background-image: url(img/1.gif);"
    v-bind:style="{
    'width':(ball.clipwidthheight-2)+'px',
    'height':(ball.clipwidthheight-2)+'px',
    'border-radius':((rotateYDeg($index,ball.clips.length)==90)||(rotateYDeg($index,ball.clips.length)==-90)?'100% !important':''),
    'transform':'rotateY('+rotateXDeg($index)+'deg) '
    +'rotateX('+rotateYDeg($index,ball.clips.length)+'deg) '
    +(rotateYDeg($index,ball.clips.length)>0?'rotateZ(180deg)':'')
    +' translateZ('+(ballR+ball.hanasuR+b.hanasu)+'px)'
    +' scale('+(b.hanasu/20+1)+')',
    }">
    </div>
  </div>
</div>
<span>
  鼠标按住拖动位置滚轮缩放,Alt+拖动/滚轮=旋转
</span>
<span>
  块大小
</span>
<input type="range" v-model="ball.clipwidthheight" min="1" max="100">
<span>
  {{ball.clipwidthheight}}
</span>
<span>
  离心距离
</span>
<input type="range" v-model="ball.hanasuR" min="1" max="100">
<span>
  {{ball.hanasuR}}
</span>
* {
  -webkit-user-select: none;
  -ms-user-select: none;
  -moz-user-select: none;
}

#canvas {
  transform-style: preserve-3d;
  perspective: 5000px;
  -webkit-transform-style: preserve-3d;
  -webkit-perspective: 5000px;
  -moz-transform-style: preserve-3d;
  -moz-perspective: 5000px;
  -ms-transform-style: preserve-3d;
  -ms-perspective: 5000px;
}

#canvas >* {
  transform-style: preserve-3d;
  perspective: 5000px;
  -webkit-transform-style: preserve-3d;
  -webkit-perspective: 5000px;
  -moz-transform-style: preserve-3d;
  -moz-perspective: 5000px;
  -ms-transform-style: preserve-3d;
  -ms-perspective: 5000px;
}

.object3d {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0px;
  height: 0px;
  transform-origin: center;
}

.clip {
  transform-origin: center;
  transition: transform 0.5s;
  width: 18px;
  height: 18px;
  top: -10px;
  left: -10px;
  background: rgba(255, 0, 0, 0.3);
  border: inset 1px rgba(0, 0, 0, 0.3);
  position: absolute;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
}

本项目引用的自定义外部资源