全景热点标签
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/dnalogelyarn add @realsee/dnalogelpnpm 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: PanoTagPluginControllerplugin.PanoTagPluginController.load(data: Tags): Promise<void>load(const data: {
tagList: Tag[];
}data)
核心方法
载入插件数据
全量加载数据(会覆盖之前的数据)
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.load(data: Tags): Promise<void>load(const data: {
tagList: Tag[];
}data)增量添加数据
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.addTag(tag: Tag | Tag[]): Promise<void>addTag(let tag: anytag)清除标签数据
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.clearTags(): voidclearTags()修改标签配置
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.changeConfig(config: Pick<Tags, "globalConfig" | "contentTypeConfig">, merge?: boolean | undefined): voidchangeConfig({ 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: PanoTagPluginControllerplugin.PanoTagPluginController.changeGlobalConfig(globalConfig: TagConfig<"Audio" | "Text" | "ImageText" | "Image" | "Video" | "Link" | "Sticker" | "VRLink" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Model" | "Panorama" | "Custom" | "Unknown"> | undefined, merge?: boolean | undefined): voidchangeGlobalConfig(let globalConfig: anyglobalConfig)
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.changeContentTypeConfig<any>(key: any, contentTypeConfig: TagConfig<any> | TagConfig<any>, merge?: boolean | undefined): voidchangeContentTypeConfig(let contentTypeKey: anycontentTypeKey, let config: anyconfig)启用/禁用/展示/隐藏/销毁
// 开启插件
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.enable(params?: {
userAction?: boolean | undefined;
} | undefined): void启用插件,让插件能够响应交互
enable()
// 禁用插件
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.disable(params?: {
userAction?: boolean | undefined;
} | undefined): void禁用插件,让插件停止响应交互
disable()
// 显示插件
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.show(params?: {
userAction?: boolean | undefined;
} | undefined): Promise<void>展示UI
show()
// 隐藏插件
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.hide(params?: {
userAction?: boolean | undefined;
} | undefined): Promise<void>隐藏UI
hide()
// 销毁插件
const plugin: PanoTagPluginControllerplugin.PanoTagPluginController.dispose(): void插件进行销毁
dispose()修改标签数据
修改 tag.data
const plugin: PanoTagPluginControllerplugin.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): voidchangeDataById(1, let data: anydata)
// or
const const tag: BaseTag<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType> | undefinedtag = const plugin: PanoTagPluginControllerplugin.TagUtil.getTagById<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType>(id: TagId): BaseTag<...> | undefinedgetTagById(1)
const tag: BaseTag<"Model" | "Text" | "Audio" | "ImageText" | "Image" | "Video" | "Panorama" | "Link" | "VRLink" | "Sticker" | "PanoLink" | "Marketing" | "MediaPlane" | "MediaModel" | "Custom" | "Unknown", StickType> | undefinedtag?.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): voidchangeData(let data: anydata)-
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: PanoTagPluginControllerpluginInstance.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: PanoTagPluginControllerpluginInstance.PanoTagPluginController.changeConfig(config: Pick<Tags, "globalConfig" | "contentTypeConfig">, merge?: boolean | undefined): voidchangeConfig({
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: PanoTagPluginControllerpluginInstance.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: PanoTagPluginControllerpluginInstance.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: PanoTagPluginControllerpluginInstance.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: anytagData, // 标签数据
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 | undefinedvisibleConfig: {
keep?: "visible" | "hidden" | null | undefinedkeep: null,
visibleFiveMode?: TagVisibleMode | ((tag: TagInstance) => TagVisibleMode) | undefinedvisibleFiveMode: ['Panorama'],
visibleDistance?: MinMax | "unLimited" | undefinedvisibleDistance: { MinMax.min?: number | undefinedmin: 0, MinMax.max?: number | undefinedmax: 10 },
visiblePanoIndex?: "all" | "current" | number[] | undefinedvisiblePanoIndex: var undefinedundefined,
},
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;
} | undefinedunfoldedConfig: {
keep?: "unfolded" | "folded" | null | undefinedkeep: null,
autoFoldWhenHide?: false | undefinedautoFoldWhenHide: 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;
} | undefinedautoUnfold: {
enable?: boolean | undefinedenable: true,
strategy?: "MinimumDistance" | undefined自动展开:最近标签自动展开
strategy: 'MinimumDistance',
maxNumber?: number | undefinedmaxNumber: 1,
distance?: MinMax | undefineddistance: { MinMax.min?: number | undefinedmin: 0, MinMax.max?: number | undefinedmax: 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',
}