全景热点标签
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>
载入数据
// 调用 `load` 方法载入全景标签数据
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.load(data: Tags): Promise<void>
load(const data: {
tagList: Tag[];
}
data)
核心方法
载入插件数据
全量加载数据(会覆盖之前的数据)
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.load(data: Tags): Promise<void>
load(const data: {
tagList: Tag[];
}
data)
增量添加数据
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.addTag(tag: Tag | Tag[]): Promise<void>
addTag(let tag: any
tag)
清除标签数据
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.clearTags(): void
clearTags()
修改标签配置
const plugin: PanoTagPluginController
plugin.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: string & Record<never, never>]: TagConfig<any> | 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<any> | TagConfig<any> | undefined;
"[Panorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Floorplan]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Topview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Mapview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[VRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[DepthPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[XRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[PanoramaLike]"?: TagConfig<any> | TagConfig<any> | undefined;
"[ModelLike]"?: TagConfig<any> | TagConfig<any> | undefined;
Any?: TagConfig<any> | TagConfig<any> | undefined;
"Model-Audio"?: TagConfig<"Audio"> | undefined ...
按type配置
contentTypeConfig })
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.changeGlobalConfig(globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined, merge?: boolean | undefined): void
changeGlobalConfig(let globalConfig: any
globalConfig)
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.changeContentTypeConfig<any>(key: any, contentTypeConfig: TagConfig<any> | TagConfig<any>, merge?: boolean | undefined): void
changeContentTypeConfig(let contentTypeKey: any
contentTypeKey, let config: any
config)
启用/禁用/展示/隐藏/销毁
// 开启插件
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.enable(params?: {
userAction?: boolean | undefined;
} | undefined): void
启用插件,让插件能够响应交互
enable()
// 禁用插件
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.disable(params?: {
userAction?: boolean | undefined;
} | undefined): void
禁用插件,让插件停止响应交互
disable()
// 显示插件
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.show(params?: {
userAction?: boolean | undefined;
} | undefined): Promise<void>
展示UI
show()
// 隐藏插件
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.hide(params?: {
userAction?: boolean | undefined;
} | undefined): Promise<void>
隐藏UI
hide()
// 销毁插件
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.dispose(): void
插件进行销毁
dispose()
修改标签数据
修改 tag.data
const plugin: PanoTagPluginController
plugin.PanoTagPluginController.changeDataById<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown">(id: TagId, data: PartialObjectDeep<...>, deepMerge?: boolean | undefined): void
changeDataById(1, let data: any
data)
// or
const const tag: BaseTag<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType> | undefined
tag = const plugin: PanoTagPluginController
plugin.TagUtil.getTagById<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType>(id: TagId): BaseTag<...> | undefined
getTagById(1)
const tag: BaseTag<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType> | undefined
tag?.BaseTag<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType>.changeData(data: PartialObjectDeep<({
modelUrl: string;
} & {
extraData?: Object | undefined;
} & {
[key: string]: any;
}) | ({
appearance?: "line" | "plane" | undefined;
text?: string | undefined;
title?: string | undefined;
description?: string | undefined;
descriptionMaxRows?: number | ... 1 more ... | undefined;
titleMaxRows?: number | ... 1 more ... | undefined;
edit?: {
...;
} | undefined;
} & {
extraData?: Object | undefined;
} & {
[key: string]: any;
}) | ... 6 more ... | (Object & ... 1 more ... & {
[key: string]: any;
})>, deepMerge?: boolean | undefined): void
changeData(let data: any
data)
-
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): 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: string & Record<never, never>]: TagConfig<any> | 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<any> | TagConfig<any> | undefined;
"[Panorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Floorplan]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Topview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Mapview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[VRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[DepthPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[XRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[PanoramaLike]"?: TagConfig<any> | TagConfig<any> | undefined;
"[ModelLike]"?: TagConfig<any> | TagConfig<any> | undefined;
Any?: TagConfig<any> | TagConfig<any> | undefined;
"Model-Audio"?: TagConfig<"Audio"> | undefined ...
按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: string & Record<never, never>]: TagConfig<any> | 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<any> | TagConfig<any> | undefined;
"[Panorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Floorplan]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Topview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Mapview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[VRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[DepthPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[XRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[PanoramaLike]"?: TagConfig<any> | TagConfig<any> | undefined;
"[ModelLike]"?: TagConfig<any> | TagConfig<any> | undefined;
Any?: TagConfig<any> | TagConfig<any> | undefined;
"Model-Audio"?: TagConfig<"Audio"> | undefined ...
按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): 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): 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: string & Record<never, never>]: TagConfig<any> | 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<any> | TagConfig<any> | undefined;
"[Panorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Floorplan]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Topview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[Mapview]"?: TagConfig<any> | TagConfig<any> | undefined;
"[VRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[DepthPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[XRPanorama]"?: TagConfig<any> | TagConfig<any> | undefined;
"[PanoramaLike]"?: TagConfig<any> | TagConfig<any> | undefined;
"[ModelLike]"?: TagConfig<any> | TagConfig<any> | undefined;
Any?: TagConfig<any> | TagConfig<any> | undefined;
"Model-Audio"?: TagConfig<"Audio"> | undefined ...
按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): 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;
entryFromModel?: boolean | undefined;
followModelVisibility?: boolean | undefined;
alwaysShowWhenMovePano?: boolean | undefined;
visibleDistance?: MinMax | "unLimited" | undefined;
visiblePanoIndex?: "all" | "current" | number[] | 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;
} | {
enable?: boolean | undefined;
strategy?: "FoldWhenMove" | undefined;
} | undefined;
} | undefined; ...
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;
entryFromModel?: boolean | undefined;
followModelVisibility?: boolean | undefined;
alwaysShowWhenMovePano?: boolean | undefined;
visibleDistance?: MinMax | "unLimited" | undefined;
visiblePanoIndex?: "all" | "current" | number[] | 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" | "current" | number[] | 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;
} | {
enable?: boolean | undefined;
strategy?: "FoldWhenMove" | 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;
} | {
enable?: boolean | undefined;
strategy?: "FoldWhenMove" | undefined;
} | undefined
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 }
}
}
}
修改Config
参照 修改标签配置
添加自定义热点标签
热点标签中有一个标签类型叫做“自定义热点标签”,使用这个标签类型,开发者可以根据自己的业务需要,自定义添加任意符合规范的标签样式。
可以参考下面的例子:
// 添加自定义热点
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',
}