@@ -65,6 +65,11 @@ import type {
|
|||||||
GuideRouteFloorSegment,
|
GuideRouteFloorSegment,
|
||||||
GuideRouteResult
|
GuideRouteResult
|
||||||
} from '@/domain/museum'
|
} from '@/domain/museum'
|
||||||
|
import {
|
||||||
|
getPoiDisplayPolicy,
|
||||||
|
isPoiVisibilityTierAtLeast,
|
||||||
|
type PoiVisibilityTier
|
||||||
|
} from '@/domain/poiDisplay'
|
||||||
import {
|
import {
|
||||||
compareFloorsTopToBottom,
|
compareFloorsTopToBottom,
|
||||||
getFloorSortLevel
|
getFloorSortLevel
|
||||||
@@ -341,7 +346,6 @@ interface FloorOption {
|
|||||||
|
|
||||||
type RenderPoi = GuideRenderPoi
|
type RenderPoi = GuideRenderPoi
|
||||||
type PoiDisplayMode = 'core' | 'balanced' | 'detail'
|
type PoiDisplayMode = 'core' | 'balanced' | 'detail'
|
||||||
type PoiVisibilityTier = 'tight' | 'balanced' | 'full'
|
|
||||||
|
|
||||||
interface PoiSpriteUserData {
|
interface PoiSpriteUserData {
|
||||||
poi?: RenderPoi
|
poi?: RenderPoi
|
||||||
@@ -607,8 +611,6 @@ const poiHitTargetScaleMultiplier = 4.8
|
|||||||
const poiHitTargetCoreScaleMultiplier = 5.4
|
const poiHitTargetCoreScaleMultiplier = 5.4
|
||||||
const poiScreenHitRadiusPx = 64
|
const poiScreenHitRadiusPx = 64
|
||||||
const poiScreenHitRadiusCorePx = 76
|
const poiScreenHitRadiusCorePx = 76
|
||||||
const poiAmbientLabelHallSpacingPx = 92
|
|
||||||
const poiAmbientLabelServiceSpacingPx = 72
|
|
||||||
const modelLoadRetryDelaysMs = [300, 900]
|
const modelLoadRetryDelaysMs = [300, 900]
|
||||||
const adjacentPreloadDelayMs = 900
|
const adjacentPreloadDelayMs = 900
|
||||||
const manualAutoSwitchPauseMs = 1500
|
const manualAutoSwitchPauseMs = 1500
|
||||||
@@ -844,29 +846,6 @@ const syncControlInteractionOptions = (event?: PointerEvent) => {
|
|||||||
controls.touches.TWO = THREE.TOUCH.DOLLY_ROTATE
|
controls.touches.TWO = THREE.TOUCH.DOLLY_ROTATE
|
||||||
}
|
}
|
||||||
|
|
||||||
const corePoiCategories = new Set([
|
|
||||||
'poi',
|
|
||||||
'touring_poi',
|
|
||||||
'exhibition_hall',
|
|
||||||
'exhibition_hall_entrance',
|
|
||||||
'basic_service_facility',
|
|
||||||
'transport_circulation',
|
|
||||||
'accessibility_special_service'
|
|
||||||
])
|
|
||||||
|
|
||||||
const poiCategoryPriority: Record<string, number> = {
|
|
||||||
target_preview: 100,
|
|
||||||
exhibition_hall: 96,
|
|
||||||
exhibition_hall_entrance: 92,
|
|
||||||
touring_poi: 90,
|
|
||||||
poi: 86,
|
|
||||||
accessibility_special_service: 88,
|
|
||||||
basic_service_facility: 82,
|
|
||||||
business_poi: 80,
|
|
||||||
transport_circulation: 76,
|
|
||||||
operation_experience: 46
|
|
||||||
}
|
|
||||||
|
|
||||||
const isHallPoi = (poi: RenderPoi) => (
|
const isHallPoi = (poi: RenderPoi) => (
|
||||||
poi.kind === 'hall'
|
poi.kind === 'hall'
|
||||||
|| poi.primaryCategory === 'exhibition_hall'
|
|| poi.primaryCategory === 'exhibition_hall'
|
||||||
@@ -881,6 +860,13 @@ const isServiceFacilityPoi = (poi: RenderPoi) => (
|
|||||||
|
|
||||||
const isTransportPoi = (poi: RenderPoi) => poi.primaryCategory === 'transport_circulation'
|
const isTransportPoi = (poi: RenderPoi) => poi.primaryCategory === 'transport_circulation'
|
||||||
|
|
||||||
|
const getPoiPolicy = (poi: RenderPoi) => (
|
||||||
|
poi.displayPolicy || getPoiDisplayPolicy({
|
||||||
|
primaryCategory: poi.primaryCategory,
|
||||||
|
kind: poi.kind
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const poiGlyphMap: Record<string, string> = {
|
const poiGlyphMap: Record<string, string> = {
|
||||||
poi: '点',
|
poi: '点',
|
||||||
accessible_restroom: '无',
|
accessible_restroom: '无',
|
||||||
@@ -1263,15 +1249,11 @@ const getPoiGlyph = (poi: RenderPoi) => (
|
|||||||
|
|
||||||
const shouldShowPoiInCurrentMode = (poi: RenderPoi) => {
|
const shouldShowPoiInCurrentMode = (poi: RenderPoi) => {
|
||||||
const mode = getPoiDisplayMode()
|
const mode = getPoiDisplayMode()
|
||||||
|
const policy = getPoiPolicy(poi)
|
||||||
|
|
||||||
if (mode === 'core') {
|
if (!policy.markerVisible) return false
|
||||||
return corePoiCategories.has(poi.primaryCategory)
|
if (mode === 'core') return policy.allowOverview
|
||||||
}
|
if (mode === 'balanced') return policy.allowMulti
|
||||||
|
|
||||||
if (mode === 'balanced') {
|
|
||||||
return corePoiCategories.has(poi.primaryCategory) || poi.primaryCategory === 'touring_poi'
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1314,22 +1296,9 @@ const shouldShowPoiAtDistance = (poi: RenderPoi, tier: PoiVisibilityTier) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeView.value === 'floor' && isHallPoi(poi)) {
|
const policy = getPoiPolicy(poi)
|
||||||
return true
|
return policy.markerVisible
|
||||||
}
|
&& isPoiVisibilityTierAtLeast(tier, policy.minMarkerTier)
|
||||||
|
|
||||||
if (tier === 'tight') {
|
|
||||||
return corePoiCategories.has(poi.primaryCategory) && !isTransportPoi(poi)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tier === 'balanced') {
|
|
||||||
return !isTransportPoi(poi) && (
|
|
||||||
corePoiCategories.has(poi.primaryCategory)
|
|
||||||
|| poi.primaryCategory === 'touring_poi'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPoiVisibilityLimit = (tier: PoiVisibilityTier) => {
|
const getPoiVisibilityLimit = (tier: PoiVisibilityTier) => {
|
||||||
@@ -1345,7 +1314,7 @@ const getPoiScreenSpacing = (tier: PoiVisibilityTier) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getPoiPriority = (poi: RenderPoi) => {
|
const getPoiPriority = (poi: RenderPoi) => {
|
||||||
const categoryPriority = poiCategoryPriority[poi.primaryCategory] || 20
|
const categoryPriority = getPoiPolicy(poi).priority
|
||||||
const selectedBoost = poi.id === activeFocusPoiId.value ? 1000 : 0
|
const selectedBoost = poi.id === activeFocusPoiId.value ? 1000 : 0
|
||||||
const hallBoost = activeView.value === 'floor' && isHallPoi(poi) ? 40 : 0
|
const hallBoost = activeView.value === 'floor' && isHallPoi(poi) ? 40 : 0
|
||||||
const transportPenalty = isTransportPoi(poi) ? 18 : 0
|
const transportPenalty = isTransportPoi(poi) ? 18 : 0
|
||||||
@@ -1364,8 +1333,7 @@ const getPoiLabelDensityTier = (): PoiVisibilityTier => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const shouldCreateAmbientPoiLabel = (poi: RenderPoi) => (
|
const shouldCreateAmbientPoiLabel = (poi: RenderPoi) => (
|
||||||
isHallPoi(poi)
|
getPoiPolicy(poi).labelVisible
|
||||||
|| isServiceFacilityPoi(poi)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const shouldShowAmbientPoiLabel = (
|
const shouldShowAmbientPoiLabel = (
|
||||||
@@ -1375,11 +1343,9 @@ const shouldShowAmbientPoiLabel = (
|
|||||||
) => {
|
) => {
|
||||||
if (!markerVisible || activeView.value !== 'floor') return false
|
if (!markerVisible || activeView.value !== 'floor') return false
|
||||||
if (poi.id === activeFocusPoiId.value || poi.primaryCategory === 'target_preview') return false
|
if (poi.id === activeFocusPoiId.value || poi.primaryCategory === 'target_preview') return false
|
||||||
if (isHallPoi(poi)) return true
|
const policy = getPoiPolicy(poi)
|
||||||
if (isTransportPoi(poi)) return false
|
return policy.labelVisible
|
||||||
if (isServiceFacilityPoi(poi)) return densityTier === 'full'
|
&& isPoiVisibilityTierAtLeast(densityTier, policy.minLabelTier)
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPoiAmbientLabelPriority = (poi: RenderPoi) => {
|
const getPoiAmbientLabelPriority = (poi: RenderPoi) => {
|
||||||
@@ -1490,17 +1456,15 @@ const updateAmbientPoiLabels = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const spacing = isHallPoi(poi) ? poiAmbientLabelHallSpacingPx : poiAmbientLabelServiceSpacingPx
|
const spacing = getPoiPolicy(poi).labelCollisionSpacing
|
||||||
const bounds = updatePoiDomLabelPosition(labelHandle)
|
const bounds = updatePoiDomLabelPosition(labelHandle)
|
||||||
if (!bounds) {
|
if (!bounds) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const overlaps = acceptedBounds.some((acceptedBound) => domLabelBoundsOverlap(bounds, acceptedBound, spacing))
|
const overlaps = acceptedBounds.some((acceptedBound) => (
|
||||||
|
domLabelBoundsOverlap(bounds, acceptedBound, spacing)
|
||||||
|
))
|
||||||
setPoiDomLabelVisible(labelHandle, !overlaps)
|
setPoiDomLabelVisible(labelHandle, !overlaps)
|
||||||
if (!overlaps) {
|
if (!overlaps) acceptedBounds.push(bounds)
|
||||||
acceptedBounds.push(bounds)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4802,7 +4766,7 @@ const findLoadedPoi = (poiId: string) => (
|
|||||||
const createPoiMarkerSprites = (poi: RenderPoi, markerSize: number) => {
|
const createPoiMarkerSprites = (poi: RenderPoi, markerSize: number) => {
|
||||||
const sprite = new THREE.Sprite(createPoiMaterial(poi))
|
const sprite = new THREE.Sprite(createPoiMaterial(poi))
|
||||||
const hitTarget = new THREE.Sprite(createPoiHitTargetMaterial())
|
const hitTarget = new THREE.Sprite(createPoiHitTargetMaterial())
|
||||||
const isCorePoi = corePoiCategories.has(poi.primaryCategory) || poi.primaryCategory === 'target_preview'
|
const isCorePoi = getPoiPolicy(poi).allowOverview || poi.primaryCategory === 'target_preview'
|
||||||
const hitTargetScale = markerSize * (isCorePoi ? poiHitTargetCoreScaleMultiplier : poiHitTargetScaleMultiplier)
|
const hitTargetScale = markerSize * (isCorePoi ? poiHitTargetCoreScaleMultiplier : poiHitTargetScaleMultiplier)
|
||||||
|
|
||||||
sprite.userData.baseScale = markerSize
|
sprite.userData.baseScale = markerSize
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type {
|
|||||||
MuseumPoiEntrance,
|
MuseumPoiEntrance,
|
||||||
MuseumPoiKind
|
MuseumPoiKind
|
||||||
} from '@/domain/museum'
|
} from '@/domain/museum'
|
||||||
|
import type { PoiDisplayPolicy } from '@/domain/poiDisplay'
|
||||||
|
|
||||||
export interface GuideRenderPoi {
|
export interface GuideRenderPoi {
|
||||||
id: string
|
id: string
|
||||||
@@ -19,6 +20,7 @@ export interface GuideRenderPoi {
|
|||||||
sourcePlaceId?: string
|
sourcePlaceId?: string
|
||||||
sourceSpaceId?: string
|
sourceSpaceId?: string
|
||||||
entrances?: MuseumPoiEntrance[]
|
entrances?: MuseumPoiEntrance[]
|
||||||
|
displayPolicy?: PoiDisplayPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GuideModelFloorAsset {
|
export interface GuideModelFloorAsset {
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ export interface MuseumPoi {
|
|||||||
sourcePlaceId?: string
|
sourcePlaceId?: string
|
||||||
sourceSpaceId?: string
|
sourceSpaceId?: string
|
||||||
entrances?: MuseumPoiEntrance[]
|
entrances?: MuseumPoiEntrance[]
|
||||||
|
displayPolicy?: import('@/domain/poiDisplay').PoiDisplayPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GuideLocationResolutionStatus = 'exact' | 'hallFallback' | 'candidate' | 'unavailable'
|
export type GuideLocationResolutionStatus = 'exact' | 'hallFallback' | 'candidate' | 'unavailable'
|
||||||
|
|||||||
125
src/domain/poiDisplay.ts
Normal file
125
src/domain/poiDisplay.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import type { MuseumPoiKind } from '@/domain/museum'
|
||||||
|
|
||||||
|
export type PoiVisibilityTier = 'tight' | 'balanced' | 'full'
|
||||||
|
|
||||||
|
export interface PoiDisplayPolicy {
|
||||||
|
markerVisible: boolean
|
||||||
|
labelVisible: boolean
|
||||||
|
minMarkerTier: PoiVisibilityTier
|
||||||
|
minLabelTier: PoiVisibilityTier
|
||||||
|
allowOverview: boolean
|
||||||
|
allowMulti: boolean
|
||||||
|
priority: number
|
||||||
|
labelCollisionSpacing: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PoiDisplayPolicyInput {
|
||||||
|
primaryCategory?: string
|
||||||
|
kind?: MuseumPoiKind
|
||||||
|
}
|
||||||
|
|
||||||
|
const tierRank: Record<PoiVisibilityTier, number> = {
|
||||||
|
tight: 0,
|
||||||
|
balanced: 1,
|
||||||
|
full: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isPoiVisibilityTierAtLeast = (
|
||||||
|
tier: PoiVisibilityTier,
|
||||||
|
minimum: PoiVisibilityTier
|
||||||
|
) => tierRank[tier] >= tierRank[minimum]
|
||||||
|
|
||||||
|
export const getPoiDisplayPolicy = ({
|
||||||
|
primaryCategory = '',
|
||||||
|
kind
|
||||||
|
}: PoiDisplayPolicyInput): PoiDisplayPolicy => {
|
||||||
|
const category = primaryCategory.trim().toLowerCase()
|
||||||
|
const isTarget = category === 'target_preview'
|
||||||
|
const isHall = kind === 'hall'
|
||||||
|
|| category === 'exhibition_hall'
|
||||||
|
|| category === 'exhibition_hall_entrance'
|
||||||
|
|| category === 'touring_poi'
|
||||||
|
const isSpace = kind === 'space' || category.startsWith('space_')
|
||||||
|
const isService = category === 'basic_service_facility'
|
||||||
|
|| category === 'accessibility_special_service'
|
||||||
|
|| category === 'business_poi'
|
||||||
|
const isTransport = category === 'transport_circulation'
|
||||||
|
|
||||||
|
if (isTarget) {
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: true,
|
||||||
|
minMarkerTier: 'tight',
|
||||||
|
minLabelTier: 'tight',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 1000,
|
||||||
|
labelCollisionSpacing: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHall) {
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: true,
|
||||||
|
minMarkerTier: 'tight',
|
||||||
|
// 原始 floor 视图中展厅 marker 可见即显示标签,不受更近一档缩放限制。
|
||||||
|
minLabelTier: 'tight',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 120,
|
||||||
|
labelCollisionSpacing: 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSpace) {
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: false,
|
||||||
|
minMarkerTier: 'tight',
|
||||||
|
// 普通空间保留 marker,但不参与展厅/设施环境标签层。
|
||||||
|
minLabelTier: 'full',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 50,
|
||||||
|
labelCollisionSpacing: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isService) {
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: true,
|
||||||
|
minMarkerTier: 'tight',
|
||||||
|
minLabelTier: 'full',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 80,
|
||||||
|
labelCollisionSpacing: 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTransport) {
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: false,
|
||||||
|
minMarkerTier: 'balanced',
|
||||||
|
minLabelTier: 'full',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 40,
|
||||||
|
labelCollisionSpacing: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
markerVisible: true,
|
||||||
|
labelVisible: false,
|
||||||
|
minMarkerTier: 'tight',
|
||||||
|
minLabelTier: 'full',
|
||||||
|
allowOverview: true,
|
||||||
|
allowMulti: true,
|
||||||
|
priority: 20,
|
||||||
|
labelCollisionSpacing: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import type {
|
|||||||
import type {
|
import type {
|
||||||
MuseumPoi
|
MuseumPoi
|
||||||
} from '@/domain/museum'
|
} from '@/domain/museum'
|
||||||
|
import {
|
||||||
|
getPoiDisplayPolicy
|
||||||
|
} from '@/domain/poiDisplay'
|
||||||
import {
|
import {
|
||||||
dataSourceConfig
|
dataSourceConfig
|
||||||
} from '@/config/dataSource'
|
} from '@/config/dataSource'
|
||||||
@@ -56,18 +59,25 @@ const getNow = () => (
|
|||||||
: Date.now()
|
: Date.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({
|
const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => {
|
||||||
id: poi.id,
|
const kind = poi.primaryCategory === 'touring_poi' ? 'hall' : 'facility'
|
||||||
name: poi.name,
|
return {
|
||||||
floorId: poi.floorId,
|
id: poi.id,
|
||||||
primaryCategory: poi.primaryCategory,
|
name: poi.name,
|
||||||
primaryCategoryZh: poi.primaryCategoryZh,
|
floorId: poi.floorId,
|
||||||
iconType: poi.iconType || poi.primaryCategory,
|
primaryCategory: poi.primaryCategory,
|
||||||
positionGltf: poi.positionGltf,
|
primaryCategoryZh: poi.primaryCategoryZh,
|
||||||
sourceObjectName: poi.sourceObjectName,
|
iconType: poi.iconType || poi.primaryCategory,
|
||||||
kind: poi.primaryCategory === 'touring_poi' ? 'hall' : 'facility',
|
positionGltf: poi.positionGltf,
|
||||||
hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined
|
sourceObjectName: poi.sourceObjectName,
|
||||||
})
|
kind,
|
||||||
|
hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined,
|
||||||
|
displayPolicy: getPoiDisplayPolicy({
|
||||||
|
primaryCategory: poi.primaryCategory,
|
||||||
|
kind
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const toGuideRenderPoi = (poi: MuseumPoi): GuideRenderPoi => ({
|
const toGuideRenderPoi = (poi: MuseumPoi): GuideRenderPoi => ({
|
||||||
id: poi.id,
|
id: poi.id,
|
||||||
@@ -84,7 +94,11 @@ const toGuideRenderPoi = (poi: MuseumPoi): GuideRenderPoi => ({
|
|||||||
spaceId: poi.spaceId,
|
spaceId: poi.spaceId,
|
||||||
sourcePlaceId: poi.sourcePlaceId,
|
sourcePlaceId: poi.sourcePlaceId,
|
||||||
sourceSpaceId: poi.sourceSpaceId,
|
sourceSpaceId: poi.sourceSpaceId,
|
||||||
entrances: poi.entrances
|
entrances: poi.entrances,
|
||||||
|
displayPolicy: poi.displayPolicy || getPoiDisplayPolicy({
|
||||||
|
primaryCategory: poi.primaryCategory.id,
|
||||||
|
kind: poi.kind
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const toSgsRenderPoi = (poi: ReturnType<typeof toMuseumPoiFromSgs>) => toGuideRenderPoi(poi)
|
const toSgsRenderPoi = (poi: ReturnType<typeof toMuseumPoiFromSgs>) => toGuideRenderPoi(poi)
|
||||||
|
|||||||
37
tests/unit/PoiDisplayPolicy.spec.ts
Normal file
37
tests/unit/PoiDisplayPolicy.spec.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import {
|
||||||
|
getPoiDisplayPolicy,
|
||||||
|
isPoiVisibilityTierAtLeast
|
||||||
|
} from '@/domain/poiDisplay'
|
||||||
|
|
||||||
|
describe('POI 显示策略', () => {
|
||||||
|
it('空间点位初始总览保留 marker,但不进入环境标签层', () => {
|
||||||
|
const policy = getPoiDisplayPolicy({
|
||||||
|
primaryCategory: 'space_public_area',
|
||||||
|
kind: 'space'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(policy.labelVisible).toBe(false)
|
||||||
|
expect(policy.minMarkerTier).toBe('tight')
|
||||||
|
expect(policy.allowOverview).toBe(true)
|
||||||
|
expect(policy.allowMulti).toBe(true)
|
||||||
|
expect(policy.minLabelTier).toBe('full')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('展厅和服务设施拥有不同优先级与标签密度策略', () => {
|
||||||
|
const hall = getPoiDisplayPolicy({ primaryCategory: 'exhibition_hall', kind: 'hall' })
|
||||||
|
const service = getPoiDisplayPolicy({ primaryCategory: 'business_poi', kind: 'facility' })
|
||||||
|
|
||||||
|
expect(hall.labelVisible).toBe(true)
|
||||||
|
expect(hall.minLabelTier).toBe('tight')
|
||||||
|
expect(hall.priority).toBeGreaterThan(service.priority)
|
||||||
|
expect(service.minLabelTier).toBe('full')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('LOD tier 按 tight 到 full 单调放宽', () => {
|
||||||
|
expect(isPoiVisibilityTierAtLeast('tight', 'tight')).toBe(true)
|
||||||
|
expect(isPoiVisibilityTierAtLeast('balanced', 'tight')).toBe(true)
|
||||||
|
expect(isPoiVisibilityTierAtLeast('balanced', 'full')).toBe(false)
|
||||||
|
expect(isPoiVisibilityTierAtLeast('full', 'balanced')).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user