Skip to content

Commit

Permalink
Merge pull request #263 from Smithsonian/rc-39
Browse files Browse the repository at this point in the history
Rc 39 merge
  • Loading branch information
gjcope authored Mar 28, 2024
2 parents e1c6a41 + 0174850 commit e4efdba
Show file tree
Hide file tree
Showing 23 changed files with 634 additions and 350 deletions.
295 changes: 8 additions & 287 deletions package-lock.json

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions source/client/annotations/AnnotationSprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import HTMLSprite, { SpriteElement, html } from "@ff/three/HTMLSprite";

import Annotation from "../models/Annotation";
import CVAssetReader from "client/components/CVAssetReader";
import AnnotationOverlay from "client/ui/explorer/AnnotationOverlay";

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -66,6 +67,7 @@ export default class AnnotationSprite extends HTMLSprite
static readonly typeName: string = "Annotation";

isAdaptive = true;
isAnimating = false;
assetManager = null;
audioManager = null;

Expand Down Expand Up @@ -140,6 +142,25 @@ export default class AnnotationSprite extends HTMLSprite
export class AnnotationElement extends SpriteElement
{
protected sprite: AnnotationSprite;
protected isTruncated: boolean = false;
protected isOverlayed: boolean = false;

get truncated()
{
return this.isTruncated
}
set truncated(value: boolean)
{
this.isTruncated = value;
}
get overlayed()
{
return this.isOverlayed
}
set overlayed(value: boolean)
{
this.isOverlayed = value;
}

constructor(sprite: AnnotationSprite)
{
Expand All @@ -166,4 +187,15 @@ export class AnnotationElement extends SpriteElement
{
event.stopPropagation();
}

showOverlay(content: HTMLElement)
{
this.requestUpdate().then(() => {
AnnotationOverlay.show(this.parentElement, content, this.sprite).then(() => {
this.overlayed = false;
this.append(content); // attach content back to original container
this.requestUpdate();
});
});
}
}
121 changes: 90 additions & 31 deletions source/client/annotations/CircleSprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export default class CircleSprite extends AnnotationSprite

protected offset: Group;
protected anchorMesh: Mesh;
protected adaptive = true;
protected originalHeight;
protected originalWidth;

constructor(annotation: Annotation)
{
Expand Down Expand Up @@ -112,42 +115,87 @@ export default class CircleSprite extends AnnotationSprite

this.offset.visible = isShowing;

// update adaptive settings
if(this.adaptive !== this.isAdaptive) {
if(!this.isAdaptive) {
element.truncated = false;
element.classList.remove("sv-short");
element.requestUpdate();
}
this.adaptive = this.isAdaptive;
}

// don't show if behind the camera
this.setVisible(!this.isBehindCamera(this.offset, camera) && isShowing);
if(!this.getVisible()) {
element.setVisible(this.getVisible());
}

// check if annotation is out of bounds and update if needed
if (annotation.expanded) {
element.classList.add("sv-expanded");

let x = element.getBoundingClientRect().left - container.getBoundingClientRect().left;
let y = element.getBoundingClientRect().top - container.getBoundingClientRect().top;

if (x + element.offsetWidth >= container.offsetWidth && !element.classList.contains("sv-align-right")) {
element.classList.add("sv-align-right");
element.requestUpdate();
}
else if (x + element.offsetWidth < container.offsetWidth && element.classList.contains("sv-align-right")){
element.classList.remove("sv-align-right");
element.requestUpdate();
}
if (y + element.offsetHeight >= container.offsetHeight && !element.classList.contains("sv-align-bottom")) {
element.classList.add("sv-align-bottom");
element.requestUpdate();
}
else if (y + element.offsetHeight < container.offsetHeight && element.classList.contains("sv-align-bottom")) {
element.classList.remove("sv-align-bottom");
element.requestUpdate();
if (this.adaptive && !this.isAnimating && annotation.expanded) {

if(!element.truncated) {
if(!element.classList.contains("sv-expanded")) {
element.requestUpdate().then(() => {
this.originalHeight = element.offsetHeight;
this.originalWidth = element.offsetWidth;
this.checkTruncate(element, container);
});
}
else {
this.originalHeight = element.offsetHeight;
this.originalWidth = element.offsetWidth;
}
}

this.checkTruncate(element, container);
}
}

protected createHTMLElement()
{
return new CircleAnnotation(this);
}

// Helper function to check if annotation should truncate
protected checkTruncate(element: AnnotationElement, container: HTMLElement) {
const x = element.getBoundingClientRect().left - container.getBoundingClientRect().left;
const y = element.getBoundingClientRect().top - container.getBoundingClientRect().top;

const shouldTruncate = y + this.originalHeight >= container.offsetHeight;
if(shouldTruncate !== element.truncated) {
element.truncated = shouldTruncate;
element.requestUpdate().then(() => {
this.checkBounds(element, container);
});
}
else {
this.checkBounds(element, container);
}
}

// Helper function to check and handle annotation overlap with bounds of container
protected checkBounds(element: AnnotationElement, container: HTMLElement) {
const x = element.getBoundingClientRect().left - container.getBoundingClientRect().left;
const y = element.getBoundingClientRect().top - container.getBoundingClientRect().top;

if (x + element.offsetWidth >= container.offsetWidth && !element.classList.contains("sv-align-right")) {
element.classList.add("sv-align-right");
element.requestUpdate();
}
else if (x + element.offsetWidth < container.offsetWidth && element.classList.contains("sv-align-right")){
element.classList.remove("sv-align-right");
element.requestUpdate();
}
if (y + element.offsetHeight >= container.offsetHeight && !element.classList.contains("sv-align-bottom")) {
element.classList.add("sv-align-bottom");
element.requestUpdate();
}
else if (y + element.offsetHeight < container.offsetHeight && element.classList.contains("sv-align-bottom")) {
element.classList.remove("sv-align-bottom");
element.requestUpdate();
}
}
}

AnnotationFactory.registerType(CircleSprite);
Expand All @@ -169,6 +217,7 @@ class CircleAnnotation extends AnnotationElement
this.onClickArticle = this.onClickArticle.bind(this);
this.onClickAudio = this.onClickAudio.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.onClickOverlay = this.onClickOverlay.bind(this);

this.markerElement = this.appendElement("div");
this.markerElement.classList.add("sv-marker");
Expand Down Expand Up @@ -197,17 +246,20 @@ class CircleAnnotation extends AnnotationElement

const annotation = this.sprite.annotation;
const annotationData = annotation.data;
const isTruncated = !this.overlayed && this.truncated
&& (annotationData.imageUri || annotationData.articleId || annotation.lead.length > 0); // make sure we have content to truncate
const audio = this.sprite.audioManager;

// update title
this.markerElement.innerText = annotationData.marker;

const contentTemplate = html`
<div class="sv-title">${annotation.title}</div>
${annotationData.imageUri ? html`<div><img alt="${annotation.imageAltText}" src="${this.sprite.assetManager.getAssetUrl(annotationData.imageUri)}">${annotation.imageCredit ? html`<div class="sv-img-credit">${annotation.imageCredit}</div>` : null}</div>` : null}
<div class="sv-content"><p>${unsafeHTML(annotation.lead)}</p></div>
${annotationData.audioId ? html`<div id="audio_container" @pointerdown=${this.onClickAudio}></div>` : null}
${annotationData.articleId ? html`<ff-button inline text="Read more..." icon="document" @click=${this.onClickArticle}></ff-button>` : null}`;
${!this.isOverlayed ? html`<div class="sv-title">${annotation.title}</div>` : null}
${annotationData.imageUri && !isTruncated ? html`<div><img alt="${annotation.imageAltText}" src="${this.sprite.assetManager.getAssetUrl(annotationData.imageUri)}">${annotation.imageCredit ? html`<div class="sv-img-credit">${annotation.imageCredit}</div>` : null}</div>` : null}
${!isTruncated ? html`<div class="sv-content"><p>${unsafeHTML(annotation.lead)}</p></div>` : null}
${annotationData.audioId && !this.isOverlayed ? html`<div id="audio_container" @pointerdown=${this.onClickAudio}></div>` : null}
${annotationData.articleId && !isTruncated ? html`<ff-button inline text="Read more..." icon="document" @click=${this.onClickArticle}></ff-button>` : null}
${isTruncated ? html`<ff-button inline text="+more info" @pointerdown=${this.onClickOverlay}></ff-button>` : null}`;

render(contentTemplate, this.contentElement);

Expand All @@ -221,7 +273,7 @@ class CircleAnnotation extends AnnotationElement
}

// update expanded/collapsed
if (this.isExpanded !== annotationData.expanded) {
if (this.isExpanded !== annotationData.expanded && !this.overlayed) {

this.isExpanded = annotationData.expanded;

Expand All @@ -233,7 +285,7 @@ class CircleAnnotation extends AnnotationElement
this.classList.add("sv-expanded");
//this.style.minWidth = annotationData.lead.length < 40 && (!annotationData.audioId || annotationData.audioId.length == 0) ? "0" : "";
this.contentElement.style.display = "block";
this.contentElement.style.height = this.contentElement.scrollHeight + "px";
this.contentElement.style.height = "auto"; //this.contentElement.scrollHeight + "px";
}
else {
this.classList.remove("sv-expanded");
Expand All @@ -257,7 +309,7 @@ class CircleAnnotation extends AnnotationElement
}

const audioView = this.querySelector(".sv-audio-view");
if(annotationData.audioId) {
if(annotationData.audioId && !this.overlayed) {
if(annotationData.expanded && !audioView) {
const audioContainer = this.querySelector("#audio_container");
audioContainer.append(audio.getPlayerById(annotationData.audioId));
Expand All @@ -281,10 +333,17 @@ class CircleAnnotation extends AnnotationElement
this.sprite.emitLinkEvent(this.sprite.annotation.data.articleId);
}

protected onClickOverlay(event: MouseEvent)
{
event.stopPropagation();
const content = this.contentElement;
this.overlayed = true;
this.showOverlay(content);
}

protected onClickAudio(event: MouseEvent)
{
event.stopPropagation();
this.sprite.emitClickEvent();
}

protected onKeyDown(event: KeyboardEvent)
Expand Down
Loading

0 comments on commit e4efdba

Please sign in to comment.