全景热点标签
PanoTagPlugin
功能说明
全景热点标签插件 提供在全景模式下标注房源不同位置热点标签信息。
详细功能点如下:
- 热点标签共分为“音频标签(Audio)”、“文本标签(Text)”、“图文标签(ImageText)”、“VR 跳转标签(Link)”、“营销标签(Marketing)”、“图片视频贴片(MediaPlane)”、“自定义标签(Custom)”等。
- 标签按照维度类型(DimensionType)可以分为:“2D(Two)”和“3D(Three)”两种。
- 按照点位类型(PointType)来分,标签又可以分为:点标记(PointTag)和平面标记(PlaneTag)两种。
- 用户可以自由组合上述标签分类属性,根据自己的业务类型,创造更加适合的全景热点标签。
示例效果
安装引用
请按需选择 yarn
或 npm
安装方式:
- npm
- Yarn
- pnpm
npm install @realsee/dnalogel
yarn add @realsee/dnalogel
pnpm add @realsee/dnalogel
通过 es 引用:
import { PanoTagPlugin } from '@realsee/dnalogel'
开发指南
初始化
在初始化 Five
实例时,将 PanoTagPlugin
配置在初始化插件参数即可。
import { Five } from '@realsee/five'
import { PanoTagPlugin } from '@realsee/dnalogel'
const five = new Five({
plugins: [
[
PanoTagPlugin,
'panoTagPlugin', // 自定义插件名称
{
// 参数配置
},
],
],
})
React 初始化
在创建 FiveProvider
时,将 PanoTagPlugin
配置在初始化插件参数即可。
import { PanoTagPlugin } from '@realsee/dnalogel'
import { createFiveProvider, FiveCanvas } from '@realsee/five/react'
const FiveProvider = createFiveProvider({
plugins: [
[
PanoTagPlugin,
'panoTagPlugin', // 自定义插件名称
{
// 参数配置
},
],
],
})
Vue 初始化
在使用 FiveProvider
时,将 PanoTagPlugin
配置在初始化插件参数即可。
<template>
<FiveProvider :fiveInitArgs="fiveInitArgs"> </FiveProvider>
</template>
<script setup>
import PanoTagPlugin from '@realsee/dnalogel/libs/PanoTagPlugin'
import { FiveProvider, FiveCanvas } from '@realsee/five/vue'
const fiveInitArgs = {
plugins: [
[
PanoTagPlugin,
'panoTagPlugin', // 自定义插件名称
{
// 参数配置
},
],
],
}
</script>
载入数据
// 获取插件实例,其中 `panoTagPlugin` 是初始化时自定义的名称
const pluginInstance = five.plugins.panoTagPlugin
// 调用 `load` 方法载入全景标签数据
pluginInstance.load(tagsData, config)
核心方法
-
load:(data: Tags, config?: AddTagConfig) => void
载入插件数据 -
addTag:(tag: Tag | Tag[], config?: AddTagConfig) => void
添加标签 -
clearTags: () => void
清空所有标签 -
async show: (params?: { userAction?: boolean; withAnimation?: boolean }) => void
显示标签 -
async hide: (params?: { userAction?: boolean; withAnimation?: boolean }) => void
隐藏标签 -
enable: (params?: { userAction?: boolean }) => void
允许使用插件 -
disable: (params?: { userAction?: boolean }) => void
禁止使用插件 -
dispose: () => void
销毁插件 -
setState: (state: Partial<State>, params: { userAction?: boolean; visibleWithAnimation?: boolean }) => void
更新插件状态 -
registerRenderer: (contentType: string, renderer: ElementRenderer, config?: { usePoint?: boolean }) => (() => any)
注册标签渲染器 -
changeTagNormalById: (id: TagId, normal: ArrayPosition) => void
修改标签位置信息 -
changeDataById: (id: TagId, data: PartialDeep<Tag<C>['data']>, deepMerge = true) => void
改变 data -
changeTagById: (id: TagId,tag: PartialDeep<{ [P in keyof Pick<Tag<C>, 'enabled' | 'style' | 'dimensionType' | 'contentType' | 'data' | 'normal'>]: Tag[P] }>,deepMerge = true,) => void
改变 tag 任意属性 -
destroyTagById: (id: TagId | TagId[]) => void
销毁 tag -
pauseCurrentMedia: () => void
暂停当前标签内进行的所有多媒体
热点标签配置
热点标签可以通过丰富的配置来实现各种不同的标签展示效果:
添加 config
- load 时添加
const const globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
globalConfig: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const const TextTagConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TextTagConfig: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const pluginInstance: PanoTagPluginController
pluginInstance.PanoTagPluginController.load(data: Tags, config?: AddTagConfig | undefined): Promise<void>
load({
Tags.tagList: Tag<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown", StickType>[]
标签列表配置tagList: [],
Tags.globalConfig?: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined
全局配置globalConfig: const globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
globalConfig,
Tags.contentTypeConfig?: {
[x: `Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Model]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Panorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Floorplan]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Topview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Mapview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[VRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[DepthPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[XRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[PanoramaLike]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[ModelLike]-Mixin-${string}`]: TagConfig<any> | undefined;
Audio?: TagConfig<"Audio"> | undefined;
Text?: TagConfig<"Text"> | undefined;
ImageText?: TagConfig<"ImageText"> | undefined;
Image?: TagConfig<"Image"> | undefined;
Video?: TagConfig<"Video"> | undefined;
Link?: TagConfig<"Link"> | undefined;
Sticker?: TagConfig<"Sticker"> | undefined;
VRLink?: TagConfig<"VRLink"> | undefined;
PanoLink?: TagConfig<"PanoLink"> | undefined;
Marketing?: TagConfig<"Marketing"> | undefined;
MediaPlane?: TagConfig<"MediaPlane"> | undefined;
MediaModel?: TagConfig<"MediaModel"> | undefined;
Model?: TagConfig<"Model"> | undefined;
Panorama?: TagConfig<"Panorama"> | undefined;
Custom?: TagConfig<"Custom"> | undefined;
Unknown?: TagConfig<"Unknown"> | undefined;
"[Model]"?: TagConfig<never> | undefined;
"[Panorama]"?: TagConfig<never> | undefined;
"[Floorplan]" ...
按type配置contentTypeConfig: {
'Text': const TextTagConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TextTagConfig
}
})
- 实时切换
import { interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig } from '@realsee/dnalogel'
const const globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
globalConfig: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const const contentTypeConfig: {
Text: {};
}
contentTypeConfig = {
'Text': {}
}
const pluginInstance: PanoTagPluginController
pluginInstance.PanoTagPluginController.changeConfig(config: Pick<Tags, "globalConfig" | "contentTypeConfig">, merge?: boolean | undefined): void
changeConfig({
globalConfig?: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined
全局配置globalConfig,
contentTypeConfig?: {
[x: `Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Model]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Panorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Floorplan]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Topview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Mapview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[VRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[DepthPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[XRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[PanoramaLike]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[ModelLike]-Mixin-${string}`]: TagConfig<any> | undefined;
Audio?: TagConfig<"Audio"> | undefined;
Text?: TagConfig<"Text"> | undefined;
ImageText?: TagConfig<"ImageText"> | undefined;
Image?: TagConfig<"Image"> | undefined;
Video?: TagConfig<"Video"> | undefined;
Link?: TagConfig<"Link"> | undefined;
Sticker?: TagConfig<"Sticker"> | undefined;
VRLink?: TagConfig<"VRLink"> | undefined;
PanoLink?: TagConfig<"PanoLink"> | undefined;
Marketing?: TagConfig<"Marketing"> | undefined;
MediaPlane?: TagConfig<"MediaPlane"> | undefined;
MediaModel?: TagConfig<"MediaModel"> | undefined;
Model?: TagConfig<"Model"> | undefined;
Panorama?: TagConfig<"Panorama"> | undefined;
Custom?: TagConfig<"Custom"> | undefined;
Unknown?: TagConfig<"Unknown"> | undefined;
"[Model]"?: TagConfig<never> | undefined;
"[Panorama]"?: TagConfig<never> | undefined;
"[Floorplan]" ...
按type配置contentTypeConfig
})
Config 种类
1. 全局 Config
const const globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
globalConfig: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const pluginInstance: PanoTagPluginController
pluginInstance.PanoTagPluginController.load(data: Tags, config?: AddTagConfig | undefined): Promise<void>
load({
Tags.tagList: Tag<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown", StickType>[]
标签列表配置tagList: [],
Tags.globalConfig?: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined
全局配置globalConfig: const globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
globalConfig
})
2. 按标签类型的config,只对指定类型的标签生效
这种设置方式全局配置也会同时生效,配置冲突时以局部配置为准
const const TextTagConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TextTagConfig: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const pluginInstance: PanoTagPluginController
pluginInstance.PanoTagPluginController.load(data: Tags, config?: AddTagConfig | undefined): Promise<void>
load({
Tags.tagList: Tag<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown", StickType>[]
标签列表配置tagList: [],
Tags.contentTypeConfig?: {
[x: `Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Model]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Panorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Floorplan]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Topview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[Mapview]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[VRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[DepthPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[XRPanorama]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[PanoramaLike]-Mixin-${string}`]: TagConfig<any> | undefined;
[x: `[ModelLike]-Mixin-${string}`]: TagConfig<any> | undefined;
Audio?: TagConfig<"Audio"> | undefined;
Text?: TagConfig<"Text"> | undefined;
ImageText?: TagConfig<"ImageText"> | undefined;
Image?: TagConfig<"Image"> | undefined;
Video?: TagConfig<"Video"> | undefined;
Link?: TagConfig<"Link"> | undefined;
Sticker?: TagConfig<"Sticker"> | undefined;
VRLink?: TagConfig<"VRLink"> | undefined;
PanoLink?: TagConfig<"PanoLink"> | undefined;
Marketing?: TagConfig<"Marketing"> | undefined;
MediaPlane?: TagConfig<"MediaPlane"> | undefined;
MediaModel?: TagConfig<"MediaModel"> | undefined;
Model?: TagConfig<"Model"> | undefined;
Panorama?: TagConfig<"Panorama"> | undefined;
Custom?: TagConfig<"Custom"> | undefined;
Unknown?: TagConfig<"Unknown"> | undefined;
"[Model]"?: TagConfig<never> | undefined;
"[Panorama]"?: TagConfig<never> | undefined;
"[Floorplan]" ...
按type配置contentTypeConfig: {
'Text': const TextTagConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TextTagConfig
}
})
2. 标签单独配置,只对单个标签生效
这种设置方式全局配置和标签类型维度的配置也会同时生效,配置冲突时以标签单独配置为准
const const TagConfig1: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TagConfig1: interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig = {}
const pluginInstance: PanoTagPluginController
pluginInstance.PanoTagPluginController.load(data: Tags, config?: AddTagConfig | undefined): Promise<void>
load({
Tags.tagList: Tag<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown", StickType>[]
标签列表配置tagList: [
{
...let tagData: any
tagData, // 标签数据
config?: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined
「展开/收起」 「可见/不可见」 的策略配置config: const TagConfig1: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown">
TagConfig1 // 只针对本标签有效
}
],
})
Config interface
const const config: {
visibleConfig?: {
keep?: "visible" | "hidden" | null | undefined;
visibleFiveMode?: TagVisibleMode | ((tag: TagInstance) => TagVisibleMode) | undefined;
followModelVisibility?: boolean | undefined;
alwaysShowWhenMovePano?: boolean | undefined;
visibleDistance?: MinMax | "unLimited" | undefined;
visiblePanoIndex?: "all" | number[] | "current" | undefined;
intersectRaycaster?: boolean | {
enabled?: boolean | undefined;
distanceAccuracy?: number | undefined;
checkPoints?: "center" | "corner" | Vector3[] | undefined;
needPassed?: number | undefined;
} | undefined;
angleRange?: MinMax | undefined;
} | ConfigFunction | undefined;
unfoldedConfig?: ConfigFunction | {
keep?: "unfolded" | "folded" | null | undefined;
autoFoldWhenHide?: false | undefined;
disableUnfold?: true | undefined;
disableFold?: true | undefined;
unfoldDistance?: MinMax | undefined;
autoUnfold?: false | {
enable?: boolean | undefined;
strategy?: "ScreenPostion" | undefined;
autoUnfoldProjectX?: MinMax | undefined;
} | {
enable?: boolean | undefined;
strategy?: "MinimumDistance" | undefined;
maxNumber?: number | undefined;
distance?: MinMax | undefined;
} | undefined;
} | undefined;
initialState?: {
visible?: boolean | undefined;
unfolded?: boolean | undefined;
} | undefined;
initialData?: (PartialObjectDeep ...
config: type Simplify<T> = { [KeyType in keyof T]: T[KeyType]; }
Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.Simplify<interface TagConfig<C extends "Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown" = "Audio" | ... 14 more ... | "Unknown">
TagConfig> = {
visibleConfig?: {
keep?: "visible" | "hidden" | null | undefined;
visibleFiveMode?: TagVisibleMode | ((tag: TagInstance) => TagVisibleMode) | undefined;
followModelVisibility?: boolean | undefined;
alwaysShowWhenMovePano?: boolean | undefined;
visibleDistance?: MinMax | "unLimited" | undefined;
visiblePanoIndex?: "all" | number[] | "current" | undefined;
intersectRaycaster?: boolean | {
enabled?: boolean | undefined;
distanceAccuracy?: number | undefined;
checkPoints?: "center" | "corner" | Vector3[] | undefined;
needPassed?: number | undefined;
} | undefined;
angleRange?: MinMax | undefined;
} | ConfigFunction | undefined
visibleConfig: {
keep?: "visible" | "hidden" | null | undefined
keep: null,
visibleFiveMode?: TagVisibleMode | ((tag: TagInstance) => TagVisibleMode) | undefined
visibleFiveMode: ['Panorama'],
visibleDistance?: MinMax | "unLimited" | undefined
visibleDistance: { MinMax.min?: number | undefined
min: 0, MinMax.max?: number | undefined
max: 10 },
visiblePanoIndex?: "all" | number[] | "current" | undefined
visiblePanoIndex: var undefined
undefined,
},
unfoldedConfig?: ConfigFunction | {
keep?: "unfolded" | "folded" | null | undefined;
autoFoldWhenHide?: false | undefined;
disableUnfold?: true | undefined;
disableFold?: true | undefined;
unfoldDistance?: MinMax | undefined;
autoUnfold?: false | {
enable?: boolean | undefined;
strategy?: "ScreenPostion" | undefined;
autoUnfoldProjectX?: MinMax | undefined;
} | {
enable?: boolean | undefined;
strategy?: "MinimumDistance" | undefined;
maxNumber?: number | undefined;
distance?: MinMax | undefined;
} | undefined;
} | undefined
unfoldedConfig: {
keep?: "unfolded" | "folded" | null | undefined
keep: null,
autoFoldWhenHide?: false | undefined
autoFoldWhenHide: false,
autoUnfold?: false | {
enable?: boolean | undefined;
strategy?: "ScreenPostion" | undefined;
autoUnfoldProjectX?: MinMax | undefined;
} | {
enable?: boolean | undefined;
strategy?: "MinimumDistance" | undefined;
maxNumber?: number | undefined;
distance?: MinMax | undefined;
} | undefined
自动展开策略, false 时不自动展开autoUnfold: {
enable?: boolean | undefined
enable: true,
strategy?: "MinimumDistance" | undefined
自动展开:最近标签自动展开strategy: 'MinimumDistance',
maxNumber?: number | undefined
maxNumber: 1,
distance?: MinMax | undefined
distance: { MinMax.min?: number | undefined
min: 0, MinMax.max?: number | undefined
max: 10 }
}
}
}
添加自定义热点标签
热点标签中有一个标签类型叫做“自定义热点标签”,使用这个标签类型,开发者可以根据自己的业务需要,自定义添加任意符合规范的标签样式。
可以参考下面的例子:
// 添加自定义热点
const addCustomerTag = () => {
// 自定义Element
const ele = document.createElement('div')
ele.innerText = '这是一个自定义的热点标签'
ele.style.color = 'red'
ele.style.width = '200px'
ele.style.border = '1px solid #000'
const tagData: Tag = {
id: '03338b76-b64a-4e90-37fb-44e3c0ffeb88',
pointType: 'PointTag',
dimensionType: '2D',
position: [-1.7882169929208833, 1.022040232156752, -2.339700937271118],
data: {
text: '自定义热点标签',
},
element: ele,
// ContentType设置为Custom
contentType: 'Custom',
}
pluginInstance.addTag(tagData)
}
自定义标签渲染器
1. 指定自定义标签类型的渲染方式
使用场景:
我通过某种方式生产了一批 contentType 为 super_tag
的标签数据,我现在想用 PanoTagPlugin
来渲染这批数据,显示结果为:<div>I'm super tag, my name is {data.name}</div>
代码示例:
const plugin = five.plugins.panoTagPlugin
/** 自定义标签组件 */
function SuperTag(props: { tag: TagInstance }) {
return <div>I'm a super tag, my name is {props.tag.data.name}</div>
}
plugin.registerRenderer('super_tag', (container: HTMLDivElement, tagInstance: TagInstance) => {
// 使用 <SuperTag> 来渲染 contentType 为 "super_tag" 的标签
ReactDOM.render(<SuperTag tag={tag}></SuperTag>, container)
// 需返回销毁函数
return () => ReactDOM.unmountComponentAtNode(container)
})
// 自定义标签数据
plugin.load({
tagList: [
{
contentType: 'super_tag',
position: [0, 1, 2],
data: {
name: 'super tag 1',
},
},
],
})
Tips:
plugin.registerRenderer
调用一次即可,无需多次调用。若不确定是否已经调用过,可以使用if (plugin.renderMap.has('My_Custom_Tag_Type')) {}
判断渲染器是否已被注册
2. 替换已有标签的渲染方式
使用场景:
我觉得PanoTagPlugin
里的文本标签(contentType: 'Text'
)太丑了,我想在数据不变的情况下自己换一套样式
代码示例:
const plugin = five.plugins.panoTagPlugin
/** 自定义文本标签组件 */
function BeautifulTextTag(props: { tag: TagInstance }) {
return <div>I'm a beautiful text tag, my title is {props.tag.data.title}</div>
}
plugin.registerRenderer('Text', (container: HTMLDivElement, tagInstance: TagInstance) => {
// 使用 <BeautifulTextTag> 来渲染 contentType 为 "Text" 的标签,替换掉默认的渲染方式
ReactDOM.render(<BeautifulTextTag tag={tag}></BeautifulTextTag>, container)
// 需返回销毁函数
return () => ReactDOM.unmountComponentAtNode(container)
})
// 原有标签数据
plugin.load({
tagList: [
{
contentType: 'Text',
position: [0, 1, 2],
data: {
title: 'text tag',
},
},
],
})
3. 使用内置的渲染器来渲染自定义标签
使用场景:
我有一套 contentType 为 My_Text
的标签数据, 我觉得PanoTagPlugin
里的文本标签样式正好符合我的需求,我想用插件内置的文本标签来渲染我这套数据,并且我无法改动原始数据类型。
代码示例:
const plugin = five.plugins.panoTagPlugin
/** 使用内置的 `Text` 标签的样式来渲染 `My_Text`标签 */
plugin.bindRenderer('My_Text', `Text`)
// 原有标签数据
plugin.load({
tagList: [
{
contentType: 'My_Text',
position: [0, 1, 2],
data: {
title: 'text tag',
},
},
],
})
4. 标签data更改时,组件数据同步更新
使用场景: 我有一个输入框,我输入的内容要实时渲染到我的自定义文本标签上
代码示例:
// 示例2中的自定义标签组件 BeautifulTextTag
function BeautifulTextTag(props: { tag: TagInstance }) {
const [data, setData] = useState(props.tag.data)
React.useEffect(() => {
// 监听 dataChanged,实时更新 state
props.tag.hooks.on('dataChanged', setData)
return () => props.tag.hooks.off('dataChanged', setData)
}, [props.tag])
return <div>inputting text is: {data.title}</div>
}
// input 输入框
function Input() {
const setText = (inputValue: string) => {
plugin.changeDataById('id', { title: inputValue })
}
return <input value={text} onChange={(e) => setText(e.target.value)} />
}
监听标签事件
支持的事件
click
单个标签点击事件playStateChange
标签内多媒体播放状态变化事件exposure
标签曝光事件show
标签插件显示事件hide
标签插件隐藏事件enable
标签插件启用事件disable
标签插件禁用事件
参考一下代码进行事件监听:
// 监听标签点击事件
pluginInstance.hooks.on("click", (params: { event: Event } & (
| { target: 'TagPoint'; tag: PointTagInstance }
| { target: 'TagContent'; tag: TagInstance }
| { target: 'AudioTagPlayIcon'; tag: TagInstance; audioInstance: HTMLAudioElement }
| { target: 'TagModel'; tag: TagInstance<'Model', 'Model'> | TagInstance<'MediaModel', 'Model'> }
) => {
console.log("click", params);
});
// 监听标签内多媒体播放状态变化事件
pluginInstance.hooks.on("playStateChange", (params: { event: Event; state: 'playing' | 'paused'; tag: TagInstance; mediaInstance: HTMLMediaElement }) => {
console.log("playStateChange", params);
});
// 监听标签曝光事件
pluginInstance.hooks.on("exposure", (params: { id: TagId; type: 'start' | 'end' }) => {
console.log("exposure", params);
});
// 监听标签插件显示事件
pluginInstance.hooks.on("show", (options: { userAction: boolean; withAnimation: boolean }) => {
console.log("show", options);
});
// 监听标签插件隐藏事件
pluginInstance.hooks.on("hide", (options: { userAction: boolean; withAnimation: boolean }) => {
console.log("hide", options);
});
// 监听标签插件启用事件
pluginInstance.hooks.on("enable", (options: { userAction: boolean }) => {
console.log("enable", options);
});
// 监听标签插件禁用事件
pluginInstance.hooks.on("disable", (options: { userAction: boolean }) => {
console.log("disable", options);
});
移除事件监听
// 移除事件监听
pluginInstance.hooks.off('click', clickHandler)
pluginInstance.hooks.off('playStateChange', playStateChangeHandler)
pluginInstance.hooks.off('exposure', exposureHandler)
pluginInstance.hooks.off('show', showHandler)
pluginInstance.hooks.off('hide', hideHandler)
pluginInstance.hooks.off('enable', enableHandler)
pluginInstance.hooks.off('disable', disableHandler)
数据结构
插件中最重要的一个结构是 Tag
,添加热点标签,修改标签信息等操作都需要使用,其对应的数据结构如下:
export type Tag<
C extends ContentType = any,
P extends PointType = any,
D extends DimensionType = any,
CustomDataType extends Object = {},
> = {
/** 开启/禁用 */
enabled?: boolean
/** 唯一标识 */
id: TagId
/** 一个点的标签/4个点的标签 */
pointType: P
/** 2维/3维类型 */
dimensionType: D
/** 内容类型,根据内容类型展示对应UI */
contentType: C
/** 点 */
position: P extends PointType.PointTag
? Position
: P extends PointType.PlaneTag
? [Position, Position, Position, Position]
: any
/** 自定义标签内容 */
element?: string | Element | ElementRenderer
/** 标签数据 */
data: C extends ContentType.Custom ? CustomDataType : ContentTypeMap[C]
/** 「展开/收起」 「可见/不可见」 的策略配置 */
config?: TagConfig<C, P, D, CustomDataType>
/** 法向量 */
normal?: Position
/** 样式 */
style?: {
/** 小圆点样式 */
point?: { style: 'Default' } | { style: 'CustomIcon'; iconUrl: string } | { style: 'noPoint' }
/** 收起的时候的动画延时,单位:ms */
foldedPointDelay?: number
}
} & (D extends DimensionType.Three
? P extends PointType.PointTag
? { normal: Position }
: unknown
: unknown) /** 三维标签需要法向量 */
标签类型定义
export enum ContentType {
/** 音频标签 */
Audio = 'Audio',
/** 文本标签 */
Text = 'Text',
/** 图文标签 */
ImageText = 'ImageText',
/** VR跳转标签 */
Link = 'Link',
/** 营销标签 */
Marketing = 'Marketing',
/** 图片视频贴片 */
MediaPlane = 'MediaPlane',
/** 其他/自定义标签 */
Custom = 'Custom',
}
标签维度类型定义
export enum DimensionType {
Two = '2D',
Three = '3D',
}
标签点位类型定义
export enum PointType {
PointTag = 'PointTag',
PlaneTag = 'PlaneTag',
}