你越是认真生活,你的生活就会越美好——弗兰克·劳埃德·莱特
《人生果实》经典语录

负责的项目想要实现链接的效果,类似VR看房,支持720°任意旋转支持自定义添加标注支持切换场景等功能

前端组长提供了掘金的麦七写的一篇博客作为参考

博客里使用Markers插件的代码在本地报错,且不完全满足我想要的效果,所以到photo-sphere-viewer官网上看了下,功能确实强大,这里基于掘金的麦七写的博客记录下我用到的内容

photo-sphere-viewer

photo-sphere-viewer插件基于three.jsuEvent 2

360°×180°全景插件photo-sphere-viewer和他的插件(这里只用到标记插件Markers

下载插件

使用npm或yarn下载安装

npm install photo-sphere-viewer

yarn add photo-sphere-viewer

文章使用的版本"photo-sphere-viewer": "^4.3.0",

使用

<template>
  <div id="viewer"></div>
</template>
<script>
    import {Viewer} from 'photo-sphere-viewer'
    import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'
    export default {
        data(){
            return{
                viewer:'',
                imgurl1:`https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6df92ba39aa94aec889582df60d3d0d0~tplv-k3u1fbpfcp-watermark.awebp`,
            }
        },
        mounted(){
            this.viewer = new Viewer({
                container:document.querySelector('#viewer'),
                panorama:this.imgurl1,
                size:{
                    width: '100vw',
                    height: '50vh',
                },
            });
        }
    }
</script>
在这里插入图片描述

常用参数

container(必需的)
类型:HTMLElement | string 包含全景图或元素标识符的HTML元素。

container: document.querySelector('.viewer')
// 或者
container: 'viewer' // will target [id="viewer"]

panorama (必需的)
类型: string | string[] | object 全景图像的路径

对于等角的全景图,它必须是单个字符串(我文章使用的就是720°全景图);
对于立方体贴图,它必须是数组或对象(对应六个面)。

// Equirectangular panorama :
panorama: 'path/to/panorama.jpg'

// Cubemap as array (order is important) :
panorama: [
  'path/to/left.jpg', 'path/to/front.jpg',
  'path/to/right.jpg', 'path/to/back.jpg',
  'path/to/top.jpg', 'path/to/bottom.jpg',
]

// Cubemap as object :
panorama: {
  left:   'path/to/left.jpg',  front:  'path/to/front.jpg',
  right:  'path/to/right.jpg', back:   'path/to/back.jpg',
  top:    'path/to/top.jpg',   bottom: 'path/to/bottom.jpg',
}

plugins
类型: array 启用的插件列表。(如后面会用到的标记插件marker)

markers:切换标记
markersList:显示标记列表
gyroscope:陀螺仪切换
stereo:切换立体声视图(VR

caption
类型: string;导航栏中显示的文本。如果导航栏被禁用,它将一直显示,但没有按钮。允许使用HTML。

size
类型: { width: integer, height: integer };最终大小(如果为全景图容器)。默认情况下,container使用的大小,并在调整窗口大小时遵循。

navbar
导航栏的配置。

autorotate :切换自动旋转
zoomOut :放大
zoomRange :缩放滑块
zoomIn :缩小
zoom:zoomOut+ zoomRange+zoomIn
download :下载源图像
caption :标题
fullscreen :切换全屏视图

自定义导航栏按钮:

 navbar: [
    {
      id: 'my-button',//按钮的唯一标识符,在使用该navbar.getButton()方法时很有用
      content: 'Custom',//必需的,按钮内容
      title: 'Hello world',//鼠标悬停在按钮上时显示工具提示
      className: 'custom-button',//CSS类已添加到按钮
      onClick: () => {
        alert('Hello from custom button');//必需的,单击按钮时调用的函数
      }
      //disabled:false,最初禁用该按钮
      //hidden:false,最初隐藏按钮
    },
  ]

更多参数参考官网

Markers插件

官方插件(在左侧菜单中列出)可在目录photo-sphere-viewer内的主软件包中找到dist/plugins。一些插件还具有其他CSS文件。

import MarkersPlugin from 'photo-sphere-viewer/dist/plugins/markers'
import 'photo-sphere-viewer/dist/plugins/markers.css';

按参考的文章导入 发现获取不到 MarkersPlugin

node_modules\photo-sphere-viewer\dist\plugins\markers.js文件里看了源码后发现

源码中有一行代码导出

exports.MarkersPlugin = MarkersPlugin;

导入改为下面的代码 可以正常获取到MarkersPlugin

import { MarkersPlugin } from 'photo-sphere-viewer/dist/plugins/markers'
import 'photo-sphere-viewer/dist/plugins/markers.css'

使用

所有插件均包含一个JavaScript类,该类必须提供给plugins数组。一些插件还将采用嵌套数组中提供的配置对象。

this.viewer = new Viewer({
    container:document.querySelector('#viewer'),
    panorama:this.imgurl1,
    size:{
        width: '100vw',
        height: '50vh',
    },
    plugins: [
        [MarkersPlugin, {
            markers: [
                {
                    id:'circle',
                    tooltip:'A circle of radius 30',
                    circle:30,
                    svgStyle : {
                        fill:'rgba(255,255,0,0.3)',
                        stroke:'yellow',
                        strokeWidth:'2px',
                    },
                    longitude: -1.5,
                    latitude: -0.28,
                    anchor: 'center right',
                }
            ],
        }],
    ],
});

初始化之后,可以使用getPlugin方法获得插件实例,从而允许在插件上调用方法并订阅事件。

const markersPlugin = this.viewer.getPlugin(MarkersPlugin);

markersPlugin.on('something', () => {
  /* ... */
});

点击查看更多标记插件的参数方法

标注效果如下
在这里插入图片描述

完整代码

下面的代码 更多是为了测试即将要开发的功能能否实现,到时开发完再贴一下最终效果图

下面代码的功能如下

  • 全景图720度旋转
  • 点击时添加自定义标注,标注会随机配置点击事件随机切换全景图
  • 标注内容通过html自定义
  • 标注存在localStorage里(没有区分是哪张全景图的)
<template>
  <div class="demo-container">
    测试
    <div id="viewer"></div>
    <ul class="item-container">
      <li
        v-for="(item, index) in itemArr"
        :key="index"
        @click="setViewer(item.img)"
      >
        {{`全景图${index+1}`}}
      </li>
    </ul>
  </div>
</template>

<script>
import { Viewer } from 'photo-sphere-viewer'
import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'

import { MarkersPlugin } from 'photo-sphere-viewer/dist/plugins/markers'
import 'photo-sphere-viewer/dist/plugins/markers.css'


export default {
  name: 'demo',
  data() {
    return {
      viewer: '',
      markersPlugin: '',
      itemArr: [
        {
          // img: require('@/assets/imgs/demo/demo1.jpeg'),
          img: 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ebbea0343bf44d2aabab3dc58aa4c3a~tplv-k3u1fbpfcp-watermark.awebp'
        },
        {
          img: 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6df92ba39aa94aec889582df60d3d0d0~tplv-k3u1fbpfcp-watermark.awebp'
        },
        {
          img: 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40135df7df034eb5a76daa76f26fe046~tplv-k3u1fbpfcp-watermark.awebp'
        },
        {
          img: 'https://img0.baidu.com/it/u=3377517910,1108839715&fm=26&fmt=auto'
        }
      ]
    }
  },
  methods: {
    setViewer(panorama) {
      if (this.viewer) try {
        this.viewer.destroy()
      } catch (e) {
        console.log(e)
        const viewer = document.querySelector('#viewer')
        viewer.removeChild(viewer.childNodes[0])
      }
      this.viewer = new Viewer({
        container: document.querySelector('#viewer'),
        panorama,
        size: {
          width: '886px',
          height: '554px'
        },
        plugins: [
          [
            MarkersPlugin,
            {
              markers: [
              ]
            }
          ]
        ]
      })
      this.viewer.once('ready', () => {
        console.log('ready')
       	// 自动旋转
        this.viewer.startAutorotate()
      })

      this.markersPlugin = this.viewer.getPlugin(MarkersPlugin)

      this.markersPlugin.on('select-marker', (e, marker) => {
        // 点击选中标注
        console.log('select-marker e:', e)
        console.log('marker:', marker)
        if (e.args[0].config.note) this.setViewer(this.itemArr[e.args[0].config.note].img)
      })

      this.viewer.on('click', (e, data) => {
        // 添加标注
        const num = 1 + Math.round(Math.random() * 2)
        console.log('num:', num)
        this.markersPlugin.addMarker({
          id: `mark${Math.random() * 10}`,
          tooltip: `213123
              <p>点击标注跳去${num + 1}全景图</p></p>
              <img style="width:100px;height:100px;" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp0.ssl.cdn.btime.com%2Ft0109595b67ee2b1409.jpg%3Fsize%3D640x400&refer=http%3A%2F%2Fp0.ssl.cdn.btime.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638584229&t=abda6688f0689b74f3a20368e31f65c1" />
          `,
          html: `
            <p class="remark">点击标注跳去${num + 1}全景图</p>
            <p class="remark">这里是标记${
  Math.floor(data.longitude * 100) / 100
} - ${Math.floor(data.latitude * 100) / 100}
            </p>
            <img  src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fhbimg.b0.upaiyun.com%2F8d8c9a2823b7d858dd653159e3eb1c47b5032c32482e1-q2bcDa_fw658&refer=http%3A%2F%2Fhbimg.b0.upaiyun.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638586036&t=475f829a3056851b1def0ec6de05a596" />
            `,
          longitude: data.longitude,
          latitude: data.latitude,
          anchor: 'center center',
          note: num
        })
        let configArr = Object.keys(this.markersPlugin.markers).map(
          (item) => this.markersPlugin.markers[item].config
        )
        localStorage.setItem('configArr', JSON.stringify(configArr))
      })
    }
  },
  mounted() {
    this.setViewer(this.itemArr[0].img)
    const configArr = JSON.parse(localStorage.getItem('configArr'))
    this.viewer.once('ready', () => {
      configArr.forEach((item) => {
        this.markersPlugin.addMarker(item)
      })
    })
  }
}
</script>

<style lang="scss" scoped>
.demo-container {
  position: relative;
  min-width: 1439px;
  margin: 0 auto;

  #viewer {
    margin: 0 auto;

    ::v-deep .psv-container {

      .psv-marker {
        border: 1px solid  white;
        padding: 10px;

        .remark {
          padding: 10px 15px;
          color: white;
        }
        img {
          width: 20px;
          height: 20px;
          margin: 0 auto;
          display: block;
        }
      }

      .psv-tooltip {
        .psv-tooltip-content {
          img {
            width: 100px;
            height: 100px;
            margin: 0 auto;
            display: block;
          }
        }
      }
    }
  }

  .item-container {
    text-align: center;
    margin-top: 20px;
    li {
      cursor: pointer;
      display: inline-block;
      padding: 10px 20px;
      &:hover {
        background-color: blue;
        color: white;
      }
    }
  }
}
</style>

项目中效果图

全景图编辑标注
在这里插入图片描述

推荐阅读

photo-sphere-viewer中文文档

photo-sphere-viewer中文文档

Vue源码学习目录

Vue源码学习完整目录


谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~
让我们一起 变得更强

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐