亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JS仿照3D手辦模型展臺實(shí)現(xiàn)示例詳解

 更新時間:2022年09月22日 15:32:25   作者:夏無涼風(fēng)冬有雪  
這篇文章主要為大家介紹了JS 實(shí)現(xiàn)偽3D手辦模型展臺示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

前幾年實(shí)現(xiàn)的一個 demo 效果,今天翻出來整理下,給大家提供類似場景參考思路。

當(dāng)時的需求場景是需要 3D 展示手辦模型,但是因?yàn)榧追筋A(yù)算有限,問有沒有其他青春版(性價比)方案。

剛好那段時間在處理 lottie 動畫跳幀的問題,就提出了給模型拍個全身照,旋轉(zhuǎn)的時候逐幀播放達(dá)到模擬手辦模型旋轉(zhuǎn)的動畫效果。

眾所周知,幀率越高,單位時間內(nèi)圖像幀的個數(shù)就會越多,對應(yīng)動畫效果就會越流暢,當(dāng)然了,對應(yīng)需要準(zhǔn)備的模型素材也就越多。

效果預(yù)覽

代碼片段

為了省流,這里沒有預(yù)渲染圖片資源,??可能出現(xiàn)轉(zhuǎn)動太快,圖片未加載的情況,請??等待片刻

style

body {
  padding: 24px;
}
.model-box {
  box-shadow: 0 10px 40px #00000029;
  padding: 24px;
  margin: 12px 0;
  border-radius: 12px;
  h4 {
    margin: 12px 0;
  }
  span {
    font-size: 12px;
  }
}
.content-box {
  position: relative;
  width: 318px;
  height: 300px;
  border: 1px solid #2196f3;
  border-radius: 20px;
  margin: 0 auto;
  img {
    position: absolute;
    top: 50%;
    pointer-events: none;
    width: 100%;
    transform: translateY(-50%);
  }
}

Script

<template>
  <div class="model-box">
    <button @click="auto">切換為自動旋轉(zhuǎn)</button>
    <h4>模型展臺 旋轉(zhuǎn)狀態(tài):{{ autoPlay ? '自動' : '手動'}} <span>(左右滑動旋轉(zhuǎn)模型)</span></h4>
    <div class="content-box" ref="content">
      <img
        v-for="(item, i) in modelImgs"
        v-show="i === activeIndex"
        :key="i"
        :src="item"
      />
    </div>
  </div>
</template>
<script>
class ModelBooth {
  constructor ({ el, event, total }) {
    this.$el = el
    this.$event = event
    this.data = {
      total: total,
      index: 0,
      x: 0,
      y: 0
    }
    this.change = this.throttle(this.emitChange.bind(this), 50)
  }
  init () {
    this.addListener()
  }
  addListener () {
    this.$el.addEventListener('touchstart', (e) => {
      this.$event?.onStop()
      this.data.x = e.touches[0].pageX
      this.data.y = e.touches[0].pageY
    }, false)
    this.$el.addEventListener('touchmove', (e) => {
      this.$event?.onStop()
      const endx = e.changedTouches[0].pageX
      const endy = e.changedTouches[0].pageY
      const direction = this.calcDirection(this.data.x, this.data.y, endx, endy)
      switch (direction) {
        case 'left':
          e.preventDefault()
          this.change(false)
          break
        case 'right':
          e.preventDefault()
          this.change(true)
          break
      }
    }, false)
  }
  auto ({ index }) {
    this.data.index = index
    this.change(true)
  }
  throttle (fn, time){
    let t1 = 0
    return function () {
      let t2 = Date.now()
      if (t2 - t1 > time) {
        fn.apply(this, arguments)
        t1 = t2
      }
    }
  }
  emitChange (type) {
    let nowIndex = this.data.index
    if (!type) {
      ++nowIndex
    } else {
      --nowIndex
    }
    const result = ((nowIndex % this.data.total) + this.data.total) % this.data.total
    this.data.index = nowIndex
    this.$event?.onChange(result)
  }
  calcDirection (startX, startY, endX, endY) {
    const angX = endX - startX
    const angY = endY - startY
    let result = ''
    // 消除噪音
    if (Math.abs(angX) < 2 && Math.abs(angY) < 2) {
      return result
    }
    const baseAngle = 45
    const angle = this.calcAngle(angX, angY)
    if (angle >= -(baseAngle * 3) && angle <= -baseAngle) {
      result = 'left'
    } else if (angle > baseAngle && angle < (baseAngle * 3)) {
      result = 'right'
    } else if ((angle >= (baseAngle * 3) && angle <= (baseAngle * 4)) || (angle >= -(baseAngle * 4) && angle < -(baseAngle * 3))) {
      result = 'up'
    } else if (angle >= -baseAngle && angle <= baseAngle) {
      result = 'down'
    }
    return result
  }
  calcAngle (x, y) {
    return Math.atan2(x, y) * 180 / Math.PI
  }
}
export default {
  data() {
    return {
      modelImgs: Array.from({ length: 30 }).map((v, i) => `https://hi-zhang.com/assets/zip/${i}.png`),
      activeIndex: 0,
      autoPlay: false,
      playTn: null
    }
  },
  mounted () {
    this._modelBooth = new ModelBooth({
      el: this.$refs.content,
      total: this.modelImgs.length,
      event: {
        onChange: (index) => {
          this.activeIndex = index
        },
        onStop: () => {
          this.stop()
        }
      }
    })
    this._modelBooth.init()
  },
  methods: {
    stop () {
      this.autoPlay = false
      clearInterval(this.playTn)
    },
    auto () {
      this.stop()
      this.autoPlay = true
      this.playTn = setInterval(() => {
        this._modelBooth.auto({
          index: this.activeIndex
        })
      }, 50)
    }
  }
}
</script>

核心科技

  • 搭建舞臺
  • 把抓拍的各個視角模型照片,渲染到舞臺上,然后堆疊到一起備用
  • 同時段只展示一個視角的模型照片
  • 旋轉(zhuǎn)時同步視角

相信大家已經(jīng)知道如何去實(shí)現(xiàn)這個需求了,那么就再簡單貼一下相關(guān)的核心問題處理

獲取旋轉(zhuǎn)角度

監(jiān)聽 touch 事件,通過開始、結(jié)束坐標(biāo)計(jì)算移動方向

 this.$el.addEventListener('touchstart', (e) => {
  this.data.x = e.touches[0].pageX
  this.data.y = e.touches[0].pageY
}, false)
this.$el.addEventListener('touchmove', (e) => {
  const endx = e.changedTouches[0].pageX
  const endy = e.changedTouches[0].pageY
  const direction = this.calcDirection(this.data.x, this.data.y, endx, endy)
  switch (direction) {
    case 'left':
      e.preventDefault()
      this.change(false)
      break
    case 'right':
      e.preventDefault()
      this.change(true)
      break
  }
}, false)

根據(jù)坐標(biāo)計(jì)算移動方向

  calcDirection (startX, startY, endX, endY) {
    const angX = endX - startX
    const angY = endY - startY
    let result = ''
    // 消除噪音
    if (Math.abs(angX) < 2 && Math.abs(angY) < 2) {
      return result
    }
    const baseAngle = 45
    const angle = this.calcAngle(angX, angY)
    if (angle >= -(baseAngle * 3) && angle <= -baseAngle) {
      result = 'left'
    } else if (angle > baseAngle && angle < (baseAngle * 3)) {
      result = 'right'
    } else if ((angle >= (baseAngle * 3) && angle <= (baseAngle * 4)) || (angle >= -(baseAngle * 4) && angle < -(baseAngle * 3))) {
      result = 'up'
    } else if (angle >= -baseAngle && angle <= baseAngle) {
      result = 'down'
    }
    return result
  }
  calcAngle (x, y) {
    return Math.atan2(x, y) * 180 / Math.PI
  }

PC端支持 touch 事件

到這里你會發(fā)現(xiàn)PC端是不支持 touch 事件的,還好這件事不是你第一個發(fā)現(xiàn)的,在 VantUI 的官方示例中,有成熟的方案,相信細(xì)心的你一定注意到了。

感慨一下,輸出技術(shù)文章還挺難的,組織措辭的時間比編碼時間還長,這還是在原有的基礎(chǔ)上整理,從頭構(gòu)建一個技術(shù)點(diǎn)的難度又是 up++++ ,以上就是JS 實(shí)現(xiàn)偽3D手辦模型展臺示例詳解的詳細(xì)內(nèi)容,更多關(guān)于JS 偽3D手辦模型展臺的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序 解決swiper不顯示圖片的方法

    微信小程序 解決swiper不顯示圖片的方法

    這篇文章主要介紹了微信小程序 解決swiper不顯示圖片的方法的相關(guān)資料,本文對swiper不顯示圖片,進(jìn)行了幾種方法排查,根據(jù)我所遇到的問題提供了該如何解決,需要的朋友可以參考下
    2017-01-01
  • JS實(shí)現(xiàn)一個可以當(dāng)鏡子照的?Button

    JS實(shí)現(xiàn)一個可以當(dāng)鏡子照的?Button

    這篇文章主要介紹了JS實(shí)現(xiàn)一個可以當(dāng)鏡子照的?Button的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 4個頂級開源JavaScript圖表庫

    4個頂級開源JavaScript圖表庫

    今天小編就為大家分享一篇關(guān)于4個頂級開源JavaScript圖表庫,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-09-09
  • 詳解微信小程序 通過控制CSS實(shí)現(xiàn)view隱藏與顯示

    詳解微信小程序 通過控制CSS實(shí)現(xiàn)view隱藏與顯示

    這篇文章主要介紹了微信小程序 通過控制CSS實(shí)現(xiàn)view隱藏與顯示的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • JavaScript?Broadcast?Channel?API使用學(xué)習(xí)

    JavaScript?Broadcast?Channel?API使用學(xué)習(xí)

    這篇文章主要為大家介紹了JavaScript的api學(xué)習(xí)之Broadcast?Channel?API使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • JavaScript?對象管家?Proxy

    JavaScript?對象管家?Proxy

    這篇文章主要為大家介紹了JavaScript對象管家Proxy使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • rollup輸出的6種格式詳解

    rollup輸出的6種格式詳解

    這篇文章主要為大家介紹了rollup輸出的6種格式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 詳解微信第三方小程序開發(fā)

    詳解微信第三方小程序開發(fā)

    這篇文章主要介紹了詳解微信第三方小程序開發(fā)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • JS前端使用canvas編寫一個簽名板

    JS前端使用canvas編寫一個簽名板

    這篇文章主要為大家介紹了JS前端使用canvas編寫一個簽名板實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 微信小程序 location API接口詳解及實(shí)例代碼

    微信小程序 location API接口詳解及實(shí)例代碼

    這篇文章主要介紹了微信小程序 location API接口相關(guān)資料,這里詳細(xì)介紹了location API接口并附簡單實(shí)例代碼,需要的朋友可以參考下
    2016-10-10

最新評論