File

src/app/components/home/home.component.ts

Implements

AfterViewInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(configService: ConfigService, router: Router, ga: GoogleAnalyticsService)
Parameters :
Name Type Optional
configService ConfigService No
router Router No
ga GoogleAnalyticsService No

Methods

goToPlayground
goToPlayground()
Returns : void
openData
openData()
Returns : void
openDataOld
openDataOld()
Returns : void
openDocs
openDocs()
Returns : void
openGithub
openGithub()
Returns : void
seekVideo
seekVideo(seconds: number, id: number)
Parameters :
Name Type Optional
seconds number No
id number No
Returns : void

Properties

Public configService
Type : ConfigService
CONTIRBUTORS
Default value : CONTIRBUTORS
copyrightYear
Default value : new Date().getFullYear()
dataVersion
Type : string
Default value : 'latest'
faEnvelope
Default value : faEnvelope
faGithub
Default value : faGithub
faGlobe
Default value : faGlobe
faLinkedin
Default value : faLinkedin
faPhone
Default value : faPhone
Public ga
Type : GoogleAnalyticsService
IMAGES
Default value : IMAGES
masterSheetLink
Type : string
Default value : ''
player
Type : YouTubePlayer
Decorators :
@ViewChild('tutorialVideo')
sheetOptions
Type : SheetDetails[]
Default value : []
VIDEO_ACTIONS
Default value : VIDEO_ACTIONS
videoContainer
Type : ElementRef<HTMLElement>
Decorators :
@ViewChild('tutorialVideoContainer')
videoSectionSelected
Type : number
Default value : 0
window
Default value : window
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { YouTubePlayer } from '@angular/youtube-player';
import { faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
import { faEnvelope } from '@fortawesome/free-regular-svg-icons';
import { faGlobe, faPhone } from '@fortawesome/free-solid-svg-icons';
import { GoogleAnalyticsService } from 'ngx-google-analytics';
import { ConfigService } from '../../app-config.service';
import { GaAction, GaCategory } from '../../models/ga.model';
import { SheetDetails } from '../../models/sheet.model';
import { CONTIRBUTORS, IMAGES, VIDEO_ACTIONS } from '../../static/home';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements AfterViewInit, OnDestroy {
  window = window;
  dataVersion = 'latest';
  VIDEO_ACTIONS = VIDEO_ACTIONS;
  CONTIRBUTORS = CONTIRBUTORS;
  IMAGES = IMAGES;
  videoSectionSelected = 0;

  faLinkedin = faLinkedin;
  faGlobe = faGlobe;
  faGithub = faGithub;
  faPhone = faPhone;
  faEnvelope = faEnvelope;

  copyrightYear = new Date().getFullYear();
  masterSheetLink = '';
  sheetOptions: SheetDetails[] = [];

  @ViewChild('tutorialVideoContainer') videoContainer!: ElementRef<HTMLElement>;
  @ViewChild('tutorialVideo') player!: YouTubePlayer;

  private videoContainerResizeObserver?: ResizeObserver;

  constructor(
    public configService: ConfigService,
    private readonly router: Router,
    public ga: GoogleAnalyticsService,
  ) {
    this.configService.config$.subscribe((config) => {
      this.masterSheetLink = config['masterSheetLink'] as string;
    });

    this.configService.sheetConfiguration$.subscribe((sheetOptions) => {
      this.sheetOptions = sheetOptions;
    });
  }

  ngAfterViewInit(): void {
    const actionsDiv = document.getElementById('actionsHeight');
    if (actionsDiv) {
      actionsDiv.style.maxHeight = `${this.player.height + 50}px`;
      actionsDiv.style.overflowY = 'auto';
    }

    this.videoContainerResizeObserver = new ResizeObserver((entries) => {
      const [
        {
          contentBoxSize: [{ inlineSize: width, blockSize: height }],
        },
      ] = entries;

      this.player.width = width;
      this.player.height = height;
    });
    this.videoContainerResizeObserver.observe(this.videoContainer.nativeElement);
  }

  ngOnDestroy(): void {
    this.videoContainerResizeObserver?.disconnect();
  }

  seekVideo(seconds: number, id: number) {
    this.videoSectionSelected = id;

    this.player.pauseVideo();
    this.player.seekTo(seconds, true);
    this.player.playVideo();

    this.ga.event(GaAction.CLICK, GaCategory.HOME, `Jump to video section: ${VIDEO_ACTIONS[id].header}`);
  }

  openGithub() {
    window.open('https://github.com/hubmapconsortium/ccf-asct-reporter', '_blank');
    this.ga.event(GaAction.NAV, GaCategory.HOME, 'Open Github');
  }

  openDocs() {
    this.router.navigate(['/docs']);
    this.ga.event(GaAction.NAV, GaCategory.HOME, 'Open Docs');
  }

  openData() {
    window.open(this.masterSheetLink, '_blank');
    this.ga.event(GaAction.NAV, GaCategory.HOME, 'Open Master Tables');
  }

  openDataOld() {
    window.open(
      'https://docs.google.com/spreadsheets/d/1j_SLhFipRWUcRZrCDfNH15OWoiLf7cJks7NVppe3htI/edit#gid=1268820100',
      '_blank',
    );
    this.ga.event(GaAction.NAV, GaCategory.HOME, 'Open Old Data Tables');
  }

  goToPlayground() {
    this.router.navigate(['/vis'], {
      queryParams: { playground: 'true', selectedOrgans: 'example' },
      queryParamsHandling: 'merge',
    });
    this.ga.event(GaAction.NAV, GaCategory.HOME, 'Launch Playground Tool');
  }
}
<div class="home-container">
  <!-- NAVBAR -->
  <div class="w-100 py-3 px-5">
    <div class="d-flex justify-content-between align-items-center w-100">
      <div class="navbar-logo">
        <img src="./assets/logo-light.svg" alt="" class="w-75 logo-link" routerLink="/" />
      </div>
      <div class="navbar-options">
        <a (click)="openDocs()" class="text-white docs">Docs</a>
        <a (click)="openGithub()" class="ml-4 text-white github">GitHub</a>
        <a class="ml-4 text-white menu" [matMenuTriggerFor]="nestedMenu.childMenu">
          Master Tables
          <mat-icon class="icon">expand_more</mat-icon>
        </a>
        <app-table-nested-menu
          #nestedMenu
          [sheetDetails]="(configService.allSheetConfigurations$ | async) ?? []"
        ></app-table-nested-menu>
        <a
          (click)="
            window.open(
              'https://docs.google.com/spreadsheets/d/1j_SLhFipRWUcRZrCDfNH15OWoiLf7cJks7NVppe3htI/edit#gid=1268820100'
            )
          "
          class="text-white ml-4"
          >Old Tables</a
        >
      </div>
    </div>
  </div>

  <!-- BACKGROUND -->
  <div id="background"></div>

  <!-- TITLE -->
  <div class="container w-100">
    <div class="d-flex justify-content-center align-items-center w-100 flex-column">
      <div class="title1 mt-5 pt-4">ASCT+B REPORTER</div>
      <div class="pt-2 muted">v2.8</div>
      <div class="pt-2 text-center desc">
        The CCF ASCT+B Reporter is a visualization tool for displaying anatomical structures, cell types, and biomarker
        (ASCT+B) authored by domain experts for different human organs. The tables are used to develop a common
        coordinate framework (CCF) of the healthy human body, see also
        <span class="linker" (click)="window.open('https://hubmapconsortium.github.io/ccf', '_blank')"
          >Hubmap Consortium website</span
        >.
      </div>
      <div class="title-btn mt-4 pt-2">
        <button mat-flat-button class="go-to-vis" routerLink="/vis">Go to Visualization</button>
        <button mat-flat-button class="go-to-vis" (click)="goToPlayground()">Launch Playground</button>
        <mat-menu #menu="matMenu" class="organMenu">
          <button
            mat-menu-item
            *ngFor="let option of sheetOptions"
            class="menu-button-item"
            routerLink="/vis"
            [queryParams]="{ sheet: option.name, version: dataVersion }"
          >
            <span>{{ option.title }}</span>
          </button>
        </mat-menu>
      </div>
    </div>
  </div>

  <!-- IMAGES  -->
  <div class="container w-100 h-50 position-relative">
    <div class="d-flex justify-content-center align-items-center w-100 h-100 mt-5 pt-3 img-contail">
      <img [src]="img.path" alt="" class="w-100 home-img h-100" *ngFor="let img of IMAGES" [alt]="img.alt" />
    </div>
  </div>

  <!-- ABOUT -->
  <div class="w-100 my-5 py-5 px-5 about-main-container" id="about">
    <div class="text-center container">
      <div class="pb-2"></div>
      <span class="title2">ABOUT</span>
      <p class="mt-3 text-secondary">
        The ASCT+B Reporter is a state-of-the-art visualization tool. The video gives an overview of the functionalities
        listed below. Please use the selectors below to skip to any section you’d want to specifically know about.
      </p>
    </div>
    <div class="pt-5 mt-3"></div>
    <div class="row">
      <div class="col-xl-5 col-md-4 col-sm-6">
        <div id="actionsHeight" class="pr-3 pl-1">
          <div *ngFor="let va of VIDEO_ACTIONS; let i = index">
            <button
              class="section-selector w-100 my-2"
              (click)="seekVideo(va.sec, i)"
              [ngClass]="{ 'section-selected': i === videoSectionSelected }"
            >
              <p class="ss-header">{{ va.header }}</p>
              <p class="ss-desc">{{ va.desc }}</p>
            </button>
          </div>
        </div>
      </div>
      <div class="col-xl-7 col-md-8 col-sm-6">
        <div class="w-100 video-tutorial" id="tutorialVideo" #tutorialVideoContainer>
          <youtube-player #tutorialVideo videoId="pzUFmDhQEO8" [playerVars]="{ rel: 0, showinfo: 0 }"></youtube-player>
        </div>
      </div>
    </div>
  </div>

  <!-- SPACING -->
  <div class="w-100 mt-5 pt-5"></div>

  <!-- CONTRIBUTORS -->
  <div class="w-100 my-5 py-5 px-5">
    <div class="text-center container">
      <p class="title2">CONTRIBUTORS</p>
      <p class="mt-3 text-secondary">
        Along with various members from the MC-IU Team as well as doctors, researchers and SMEs from various consortia,
        below listed are the members of the core team working on building the ASCT+B Reporter
      </p>
    </div>
    <div class="pt-5 container">
      <div class="row">
        <div class="col-xl-4 col-md-6 col-sm-6 col-lg-4 px-3 mt-4" *ngFor="let con of CONTIRBUTORS; let i = index">
          <div class="card text-center con-card">
            <div class="card-header">
              <img class="contributors-img" alt="" [src]="con.img" alt="sans" width="140px" height="140px" />
            </div>
            <div class="card-body">
              <p class="title4">{{ con.name }}</p>
              <p class="desc text-secondary mt-2">
                {{ con.desc }}
              </p>
              <p class="desc text-muted mt-4 profile">
                <a class="text-info" [href]="'mailto:' + con.mail">{{ con.mail }}</a>
              </p>
            </div>
            <div class="card-footer border-top">
              <div class="d-flex justify-content-center align-items-center">
                <div class="mr-2">
                  <button mat-icon-button class="icon-btn" (click)="window.open(con.link, '_blank')">
                    <fa-icon [icon]="faGlobe"></fa-icon>
                  </button>
                </div>
                <div class="mr-2" *ngIf="con.linkedin">
                  <button mat-icon-button class="icon-btn" (click)="window.open(con.linkedin, '_blank')">
                    <fa-icon [icon]="faLinkedin"></fa-icon>
                  </button>
                </div>
                <div *ngIf="con.github">
                  <button mat-icon-button class="icon-btn" (click)="window.open(con.github, '_blank')">
                    <fa-icon [icon]="faGithub"></fa-icon>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- AFFILIATIONS -->
  <div class="my-5 py-5">
    <div class="container">
      <br />
      <div class="text-center">
        <p class="title2">AFFILIATIONS</p>
        <p class="mt-3 text-secondary">
          Various institutions that the CCF ASCT+B Reporter is affiliated with are listed below.
        </p>
      </div>
      <div class="affiliations-image-container p-5">
        <div class="row">
          <div class="col-lg-4 col-md-4 mt-5">
            <img
              src="assets/affiliations/iu.jpg"
              alt=""
              height="100"
              class="affiliation-img"
              (click)="window.open('https://www.indiana.edu', '_blank')"
            />
          </div>
          <div class="col-lg-4 col-md-4 mt-5">
            <img
              src="assets/affiliations/cns.png"
              alt=""
              class="affiliation-img"
              height="100"
              (click)="window.open('https://cns.iu.edu', '_blank')"
            />
          </div>
          <div class="col-lg-4 col-md-4 mt-5">
            <img
              src="assets/affiliations/hubmap.png"
              alt=""
              height="100"
              class="affiliation-img"
              (click)="window.open('https://github.com/hubmapconsortium', '_blank')"
            />
          </div>
          <br />
        </div>
      </div>
      <br />
    </div>
  </div>

  <!-- FOOTER -->
  <app-footer></app-footer>
</div>

./home.component.scss

.example-spacer {
  flex: 1 1 auto;
}
.home-container {
  width: 100%;
  height: 100%;
  position: relative;
}
.menu-button-item {
  width: 100%;
}
.menu {
  position: relative;
  color: #fff !important;
  cursor: pointer;
  margin: 1.5rem !important;
}
.menu:hover {
  text-decoration: underline;
}

.icon {
  position: absolute;
}
.about-main-container {
  position: relative;
}
.video-tutorial {
  box-shadow: 0.3125rem 1.25rem 1.875rem #e1e1e1;
  border-radius: 0.625rem;
  outline: none;
  overflow: hidden;
}
.affiliations-image-container {
  width: 100%;
  text-align: center;
}
.affiliation-img {
  cursor: pointer;
}
a {
  cursor: pointer;
}

p {
  margin: 0;
}

.dark {
  color: #262626 !important;
}

.a-nav {
  // color: #444a65;
  margin-left: 1.875rem;
  cursor: pointer;
  transition: all 0.2s;
  text-decoration: none !important;
  font-size: 0.875rem;
  color: white;
}

.a-nav:hover {
  color: #377eb8;
}

.linker {
  color: white;
  font-weight: 500;
  cursor: pointer;
}

.linker:hover {
  text-decoration: underline;
}

.go-to-vis {
  padding: 2.3rem 1rem;
  font-size: 18pt;
  border-radius: 0.625rem;
  background-color: #7fd9da;
  color: #262626;
  font-weight: bold;
  margin: 0.5rem 0.5rem;
  letter-spacing: 0.02rem;
}

.title-desc {
  text-align: justify;
  text-justify: inter-word;
  color: rgb(164, 164, 164);
  font-size: 12pt;
  hyphens: auto;
}

.title {
  font-size: 4.375rem;
  line-height: 4.6875rem;
  font-weight: 400;
  color: #444a65;
  text-align: justify;
  margin: 0 auto;
}

@media only screen and (max-width: 1000px) {
  .title {
    text-align: center;
  }
  .title-desc {
    display: flex;
    width: 100%;
    flex-direction: column;
    justify-content: center;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
  }
  .title-btn {
    display: flex;
    width: 100%;
    justify-content: center;
  }
}

.title1 {
  font-family: 'Poppins', sans-serif;
  font-size: 5.5rem;
  line-height: 5rem;
  color: white;
  font-weight: 600;
  letter-spacing: 0.5rem;
}

.title2 {
  font-family: 'Poppins', sans-serif;
  font-size: 3.125rem;
  line-height: 3.75rem;
  color: #262626;
  font-weight: 400;
  hyphens: auto;
  letter-spacing: 0.25rem;
}

.title3 {
  font-family: 'Poppins', sans-serif;
  font-size: 1.875rem;
  line-height: 1.875rem;
  color: #262626;
  font-weight: 600;
}

.title4 {
  font-family: 'Poppins', sans-serif;
  font-size: 1.25rem;
  line-height: 1.25rem;
  color: #262626;
  font-weight: 500;
}

.subtitle {
  font-size: 1rem;
  line-height: 0.9375rem;
  color: #e3e3e3;
  font-weight: 400;
}

.pro {
  border-radius: 50%;
  height: 7.5rem;
  width: 7.5rem;
  object-fit: cover;
  border: 0.125rem solid rgb(218, 218, 218);
}

.desc {
  font-size: 12pt;
  font-weight: 400;
  color: white;
  line-height: 1.5625rem;
}

.logo1 {
  margin-right: 0.625rem;
  width: 5.625rem;
  cursor: pointer;
  color: white;
}

.logo2 {
  margin-right: 0.625rem;
  width: 6.25rem;
  cursor: pointer;
  color: white;
}

/* CARDS */

.card {
  border: none;
  border-radius: 0.625rem;
  box-shadow: 0.3125rem 1.75rem 1.5625rem rgba(128, 128, 128, 0.057);
  transition: all 0.5s ease;
}

.card:hover {
  transition: all 0.5s ease;
  box-shadow: 0.3125rem 1.75rem 2.1875rem rgba(128, 128, 128, 0.226);
}

::ng-deep .organMenu {
  width: 18.75rem !important;
  height: 12.5rem !important;
}

#background {
  position: absolute;
  top: 0rem;
  left: 0rem;
  height: 75%;
  width: 100%;
  background-color: #262626;
  z-index: -1;
}

.laptop {
  position: relative;
  width: 100%;
  height: auto;
}

.laptop:after {
  content: '';
  display: block;
}

.l {
  // position: absolute;
  width: 100%;
}

.i {
  position: absolute;
  width: 80%;
  left: 7.6875rem;
  top: 1.75rem;
  z-index: -1;
}

@media (min-width: 576px) {
  .i {
    position: absolute;
    width: 80%;
    left: 5.1875rem;
    top: 1.125rem;
    z-index: -1;
  }
}

// Medium devices (tablets, 768px and up)
@media (min-width: 768px) {
  .i {
    position: absolute;
    width: 80%;
    left: 6.4375rem;
    top: 1.4375rem;
    z-index: -1;
  }
}

// Extra large devices (large desktops, 1200px and up)
@media (min-width: 1200px) {
  .i {
    position: absolute;
    width: 80%;
    left: 7.6875rem;
    top: 1.75rem;
    z-index: -1;
  }
}

.section-selector {
  text-align: left;
  outline: none;
  border: 0.125rem solid #eaeaea;
  border-radius: 0.5rem;
  padding: 0.625rem 0.625rem 0.625rem 0.625rem;
  border-left-width: 0.9375rem;
  background-color: white;
  transition: all 0.2s;
}

.section-selector:not(.active):hover {
  border-color: #444a6590;
}

.section-selector:active {
  transform: scale(0.99);
}

.section-selected {
  border-color: #444a65 !important;
}

.ss-header {
  font-family: 'Poppins', sans-serif;
  font-weight: 500;
  font-size: 14pt;
  padding-bottom: 0.3125rem;
}

.ss-desc {
  color: grey;
}

.card-img-top {
  max-height: 10vh;
  /*not want to take all vertical space*/
  object-fit: cover;
  /*show all image, autosized, no cut, in available space*/
}

.contributors-img {
  border-radius: 50%;
  object-fit: cover;
  border: 0.1875rem solid #eaeaea;
}

.con-card {
  box-shadow: none !important;
  border: 0.125rem solid #eaeaea;
  border-top-width: 0.9375rem;
  border-radius: 0.625rem;
  padding: 0.625rem;
  height: 30.375rem;
}

.icon-btn {
  height: 3.125rem;
  width: 3.125rem;
  font-size: 1.5625rem;
  line-height: 1.875rem;
  color: #262626;
}

.text-info {
  color: #444a65 !important;
}

#actionsHeight,
.video-tutorial {
  height: 450px;
}

.home-img {
  position: absolute;
  top: 0;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-duration: 8s;
  animation-name: anim;
  -webkit-animation-name: anim;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-duration: 8s;
}

.home-img:nth-child(1) {
  animation-delay: 0s;
  -webkit-animation-delay: 0s;
}

.home-img:nth-child(2) {
  animation-delay: 4s;
  -webkit-animation-delay: 4s;
}

.home-img:nth-child(3) {
  animation-delay: 8s;
  -webkit-animation-delay: 8s;
}

.home-img:nth-child(4) {
  animation-delay: 12s;
  -webkit-animation-delay: 12s;
}

.home-img:nth-child(5) {
  animation-delay: 16s;
  -webkit-animation-delay: 16s;
}

@keyframes anim {
  0% {
    opacity: 0;
    z-index: 100;
  }
  15% {
    opacity: 1;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    z-index: 1;
  }
}

.navbar-options {
  a {
    text-decoration: none;
  }
  a:hover {
    text-decoration: underline;
  }
  .docs,
  .github {
    padding-left: 1rem;
  }
}

.muted {
  color: #6c757d;
}

.profile {
  a {
    text-decoration: none;
  }
  a:hover {
    text-decoration: underline;
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""