Implementation effect

The development of preparation

  • Design drawing: spherical projection

  • Principle:
    • Cut, put together into a ball
    • You start stacking them, you rotate them at an Angle, and then you push them out along the Z axis, and you get close to a sphere

  • In this example, cut the design drawing into 20 pieces

Method 1: Do it yourself

The code structure

├─ Audio # Background Music

│ └ ─ ─ happy. Mp3

├─ CSS # Global CSS

│ └ ─ ─ index. The CSS

├─ IMG # Pictures (Background, Spherical Projection slice -20 copies)

├─ Index.html # page

├ ─ ─ script # js

│ └ ─ ─ index. Js

├ ─ └─ start. Bat # Start http-server for cell phone testing

html

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <! Viewport -->
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
  <title>Css3d creation section</title>
  <link rel="stylesheet" href="./css/index.css">
</head>

<body>
  <! -- Voice player -->
  <audio id="audio">
    <source src="./audio/happy.mp3" type="audio/mpeg">
  </audio>
  <! - the horn -- -- >
  <div id="laba">🎺</div>
  <! -- 3D container -->
  <div class="container">
    <! -- 3D box for pictures -->
    <div id='box' class="box"></div>
  </div>
  <script src="./script/zepto.min.js"></script>
  <script src="./script/index.js"></script>
</body>

</html>
Copy the code

css

  • 1rem = 16px; Rem based on the root font size, HTML default font size: 16px;
  • Each image: 129px wide by 1170px high
* {
  padding: 0;
  margin: 0;
}

body {
  background-image: url('.. /img/bg.jpg');
}

#laba {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 999;
}

.container {
  margin: 0 auto;
  width: 8.0625 rem; / * * / 129
  perspective: 25rem; /* Set the viewing distance to 400 */
}

.container .box {
  height: 100%;
  transform-style: preserve-3d;
  perspective-origin: 50% 50%; /* Set the observation center. * /
}

.container .box > div {
  position: absolute;
  width: 8.0625 rem; / * * / 129
  height: 73.125 rem; / * * / 1170
}
Copy the code

js

/** * Get DOM node * by id@param {*} id
 * @returns* /
 function _ $(id) {
  return document.getElementById(id);
}

/** * Calculate the radius *@param  Length The width of each image *@param  Count How many pictures *@return The length of the radius */
function calculateRadius(width, count) {
  // r = width of each image /2 / TRAN (degree of each image /2); Degree of each copy = 360/ number of pictures = 360/20 = 18
  // Math.PI = 180
  // Why subtract 3, because when you combine a circle, there are two edges that need to merge -2, and there is still a 1px edge, so subtract -1 from this edge
  // return Math.round(width / (2 * Math.tan((Math.PI * 2) / count / 2))) - 3;
  return Math.round(width / (2 * Math.tan(Math.PI / count))) - 3;
}

/** * Create image and layout *@param {*} $el box
 * @param {*} Len Number of images *@param {*} R Adjust the Angle */
function createDIVLayout($el, len, r) {
  // Add nodes in batches
  const fragment = document.createDocumentFragment();
  const _img_url_prefix = './img/p{n}.png';

  for (let i = 1; i <= len; i++) {
    const div = document.createElement('div');
    // The auxiliary tag can be removed
    div.innerHTML = i;
    / / set the CSS
    div.style.background = `url(${_img_url_prefix.replace(/\{n\}/g, i)}) no-repeat`;
    div.style.WebkitTransform = `rotateY(The ${(360 / len) * i}deg) translateZ(${r}px)`;

    // Add to fragment
    fragment.appendChild(div);
  }

  // Add fragment batch to $el
  $el.appendChild(fragment);
}

/* Define constant */
const IMG_LEN = 20;
const IMG_W = 129;
const radius = calculateRadius(IMG_W, IMG_LEN);

/* Get the relevant DOM node */
const box = _$('box');
const audio = _$('audio');

/* Create image and layout */
createDIVLayout(box, IMG_LEN, radius);

/* Zepto event */
// Control background music playback and pause
$('#laba').on('tap'.function () {
  if (audio.paused) {
    audio.play();
    $(this).text('⏸');
  } else {
    audio.pause();
    $(this).text('🎺'); }});// Drag the box around y
let startX = 0; // the finger starts at the X position
let endX = 0; // The X position when the finger is released
let x = 0; // The distance moved
let flag = true; // It is used to distinguish between touch triggered rotation and the phone's own rotation through the gyroscope
let touching = false;

$('#box').on('touchstart'.function (event) {
  event.preventDefault();
  const touch = event.targetTouches[0];
  startX = touch.pageX - x;
  touching = true;
});
$('#box').on('touchmove'.function (event) {
  if (flag && touching) {
    event.preventDefault();
    const touch = event.targetTouches[0];
    endX = touch.pageX;
    x = endX - startX;
    // How much x is moved is rotated about the y axis
    box.style.transform = `rotateY(${x}deg)`; }}); $('#box').on('touchend'.function () {
  touching = false;
});

// Monitor gyroscope - rotation Angle, used to change the rotation Angle of the mobile phone when it moves around the y axis
window.addEventListener('deviceorientation'.function (event) {
  const gamma = event.gamma;
  if (Math.abs(gamma) > 1) {
    flag = false;
    box.style.transform = `rotateY(${gamma * 3}deg)`; // Multiply by 3, mainly to make it faster
  } else {
    flag = true; }});Copy the code

Start the server

  • Http-server Simply enable a server for local folders, because mobile phones cannot access local files on your PC
  • Install http-server: NPM i-g http-server
  • In the current code root directory, run the http-server -p 8000 command to start the service

  • Enter http://10.1.251.161:8000 in the PC browser to verify that the page can be opened

Mobile Viewing

  • Generate qr codes for local service addresses: The forage QR code generator can be used here
  • Wechat scan code

Method 2: Use ss3D-engine

Css3d-engine is a very good css3D library, easy to get started, mainly master the following elements

  • Stage: The position we place
  • Plane: Used when building a Plane
  • Camera: Necessary for 3D scenes, think of the Camera as our eyes
  • Cube (Box): Build cubes to use
  • Skybox: Used when building panoramic backgrounds

There are three elements that make up a 3D effect: scene, object and perspective. It’s much easier to understand 3D when you have these three elements:

The code structure

├─ IMG # Pictures (Background, Spherical Projection slice -20 copies)

├─ Index.html # page

├ ─ ─ script # js

│ └ ─ ─ css3d. Js

├ ─ └─ start. Bat # Start http-server for cell phone testing

html

<! DOCTYPEhtml>
<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>
    * {
      margin: 0;
      padding: 0;
    }
  </style>
</head>

<body>
  <div id="main" style="width:500px; height:500px;"></div>
  <script type="text/javascript" src="./js/css3d.js"></script>
  <script>
    // Constract
    const PANO_RECT = { w: 2586.h: 1170 };
    const IMG_LEN = 20;
    const _img_prefix = 'img/p{n}.png'


    // Create a scene
    const s = new C3D.Stage();

    // Set the scene size and material, here is the background image
    s.size(window.innerWidth, window.innerHeight).material({
      image: 'img/bg.jpg'
    }).update();

    document.getElementById('main').appendChild(s.el);

    const createPano = rect= > {
      const _step = rect.w / IMG_LEN;
      const _radius = Math.floor(_step / 2 / Math.tan(Math.PI / IMG_LEN)) - 1;

      // Create a Sprite image
      const _sp = new C3D.Sprite();
      for (let i = 1; i <= IMG_LEN; i++) {
        const _p = new C3D.Plane();
        const _r = 360 / IMG_LEN * i;
        const _a = Math.PI * 2 / IMG_LEN * i;
        const img = _img_prefix.replace(/\{n\}/g, i);

        _p.size(_step, rect.h).position(Math.sin(_a) * _radius, 0, -Math.cos(_a) * _radius).rotation(0, -_r, 0).material({
          image: img,
          repeat: 'no-repeat'.bothsides: false,
        }).update();

        _sp.addChild(_p);
      }
      return _sp
    }

    // Build the plane
    const pano = createPano(PANO_RECT);

    pano.position(0.0, -400).updateT();

    // Insert panO into the scene
    s.addChild(pano);

    // Respond to screen resizing
    function resize() {
      s.size(window.innerWidth, window.innerHeight).update();
    }

    window.onresize = () = > resize();
    resize();

    // Refresh the scene
    requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame ||
      function (callback) {
        setTimeout(callback, 1000 / 60);
      };

    function go() {
      pano.rotate(0.0.2.0).updateT();
      requestAnimationFrame(go);
    }

    requestAnimationFrame(go);

  </script>
</body>

</html>
Copy the code