/**
 * 3D Foundation Project
 * Copyright 2019 Smithsonian Institution
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ import { Object3D , Camera , ArrayCamera , PerspectiveCamera , Vector3 } from "three" ; import { ITypedEvent } from "@ff/core/Publisher" ; import HTMLSprite , { SpriteElement , html } from "@ff/three/HTMLSprite" ; import Annotation from "../models/Annotation" ; import CVAssetReader from "client/components/CVAssetReader" ; const _vec3up = new Vector3 ( 0 , 1 , 0 ) ; const _vec3dir = new Vector3 ( ) ; const _vec3a = new Vector3 ( ) ; const _vec3b = new Vector3 ( ) ; export { Annotation , html } ; event export interface IAnnotationClickEvent extends ITypedEvent < "click" > { annotation : Annotation ; sprite : AnnotationSprite ; } event export interface IAnnotationLinkEvent extends ITypedEvent < "link" > { annotation : Annotation ; sprite : AnnotationSprite ; link : string ; } /**
 * Defines the visual appearance of an annotation.
 * An annotation consists of a 3D (WebGL) part and a 2D (HTML) part.
 *
 * ### Events
 * - *"click"* Emitted if the user clicks on the annotation.
 * - *"link"* Emitted if the user activates a link on the annotation.
 */ export default class AnnotationSprite extends HTMLSprite { static readonly typeName : string = "Annotation" ; isAdaptive = true ; returns { string } get typeName ( ) { return ( this . constructor as typeof AnnotationSprite ) . typeName ; } readonly annotation : Annotation ; constructor ( annotation , assetReader ? ) { super ( ) ; this . annotation = annotation ; this . matrixAutoUpdate = false ; } update ( ) { super . update ( ) ; const annotation = this . annotation . data ; this . position . fromArray ( annotation . position ) ; _vec3dir . fromArray ( annotation . direction ) . normalize ( ) ; this . quaternion . setFromUnitVectors ( _vec3up , _vec3dir ) ; this . updateMatrix ( ) ; } emitClickEvent ( ) { const event = { type : "click" , annotation : this . annotation , sprite : this } ; this . dispatchEvent ( event ) ; } emitLinkEvent ( link ) { const event = { type : "link" , annotation : this . annotation , sprite : this , link } ; this . dispatchEvent ( event ) ; } protected isBehindCamera ( anchor , camera ) { let matrixCamera = null ; if ( camera instanceof ArrayCamera && ( camera as ArrayCamera ) . cameras . length > 0 ) { matrixCamera = ( camera as ArrayCamera ) . cameras [ 0 ] ; } else { matrixCamera = camera ; } const e = matrixCamera . matrixWorld . elements ; anchor . updateMatrixWorld ( ) ; _vec3a . setFromMatrixPosition ( anchor . matrixWorld ) ; _vec3b . setFromMatrixPosition ( matrixCamera . matrixWorld ) ; _vec3dir . set ( - e [ 8 ] , - e [ 9 ] , - e [ 10 ] ) . normalize ( ) ; _vec3b . addScaledVector ( _vec3dir , ( matrixCamera as PerspectiveCamera ) . near ) ; _vec3b . sub ( _vec3a ) ; return _vec3b . angleTo ( _vec3dir ) <= Math . PI / 2 ; } } export class AnnotationElement extends SpriteElement { protected sprite : AnnotationSprite ; constructor ( sprite ) { super ( ) ; this . sprite = sprite ; this . discardEvent = this . discardEvent . bind ( this ) ; this . addEventListener ( "pointerdown" , this . discardEvent ) ; this . addEventListener ( "pointercancel" , this . discardEvent ) ; this . addEventListener ( "click" , this . discardEvent ) ; } protected firstConnected ( ) { super . firstConnected ( ) ; this . classList . add ( "sv-annotation" ) ; } protected discardEvent ( event ) { event . stopPropagation ( ) ; } }