2018年8月30日木曜日

AngularでyoutubeAPI(Iflame Player API)を使ってyoutube動画を埋め込み表示する。

オフィス狛 技術部のHammarです。

いろんなサイトでyoutube動画が見れるように工夫しているところが多いですが、今回はAngularでyoutubeAPI(Iflame Player API)を利用して、サイトにyoutube動画を埋め込み表示する方法を書いてみたいと思います。

■実装環境

・Angular
・ngx-youtube-playerモジュールを利用

今回使用するngx-youtube-playerモジュールはインストール済みとします。
まずモジュールのimportを記述します。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { YoutubePlayerModule } from 'ngx-youtube-player';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app';

@NgModule({
  imports: [BrowserModule, YoutubePlayerModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

platformBrowserDynamic().bootstrapModule(AppModule);

次にyoutubeを埋め込みたい画面のファイルに下記のように記述します。
このあたりの記述はnpmjs.comのサンプルの記載とほぼ同じ感じです。
import { Component } from '@angular/core';
@Component(
  selector: 'app',
  template: `
        <youtube-player
      [videoId]="id"
      (ready)="savePlayer($event)"
      (change)="onStateChange($event)"
    ></youtube-player>
    `
})

export class AppComponent {
  player: YT.Player;
  private id: string = 'qDuKsiwS5xw';

  savePlayer(player) {
    this.player = player;
  }
}

これで基本的な下準備は完了で、
private id: string = 'qDuKsiwS5xw';
の部分で対象動画のyoutubeのidをセットすれば動画の埋め込みは完了です。
すごく簡単ですね!

で、カスタマイズも結構簡単にできますので、いくつか紹介したいと思います。

■動画が完了したタイミングで何か処理をする 

上記のcomponent.tsファイルに
  onStateChange(event) {
    if (event.data === 0) {
        // 動画終了してからの処理
    }
  }
のように追記して動画終了してから自動で何か処理をさせることもできます。
動画のステータスは
    -1 – 未開始
    0 – 終了
    1 – 再生中
    2 – 一時停止
    3 – バッファリング中
    5 – 頭出し済み
で判定することができますので、ステータスが変わったタイミングでなにかの処理を入れたりすることができます。

■プレイヤーのコントロールを別ボタンでやる

たとえば動画の再生や停止をyoutube内部のコントローラーではなく、プレイヤー外部にボタンを新たに設定してそこで制御したい場合などは下記のように追記するだけで実装可能です。
まずhtml側に下記のようなボタンを作成しておきます。
<button (click)="playVideo()" ><p>再生</p></button>

component.tsファイルに下記関数を設定します。
// 再生ボタン
playVideo() {
    this.player.playVideo();
}
これだけで制御が可能になります。
上記の要領で停止や音量の変更、ミュートやシークも簡単に制御ができます。

■動画終了後の表示のカスタマイズ

動画が終了すると関連の動画も勝手に表示されたりして、表示動画とは全く違うジャンルの動画リスト等もデフォルトで表示され、サイトによっては余計な情報も表示されてしまうので、この表示をいくつか消したいときがあると思います。
このあたりの表示内容についてもカスタマイズ可能です。
動画終了後の関連動画を非表示にする場合、component.tsファイルのtemplate部分を下記のように記述します。
@Component({
  selector: 'app',
  template: `
        <youtube-player
      [videoId]="id"
      (ready)="savePlayer($event)"
      (change)="onStateChange($event)"
      [playerVars]="{'rel': 0}"
    ></youtube-player>
    `
})

上記の[playerVars]="{'rel': 0}"という記述が関連動画を非表示にするパラメータになります。
上記以外にも、動画の再生が始まる前に動画のタイトルやアップロードしたユーザーなどの情報カスタマイズや、動画のプレーヤーコントロールを表示するかどうかを指定したりすることができます。

上記で紹介したのはほんの一部で、下記公式サイトにいろいろなカスタマイズのリファレンスやプレイヤーパラメータの詳細が載っていますので、ぜひ参考にしてみてください。

・Iflame Player APIリファレンス
https://developers.google.com/youtube/iframe_api_reference?hl=ja#Playback_controls
・youtubeプレイヤーパラメータ
https://developers.google.com/youtube/player_parameters?playerVersion=HTML5&hl=ja

,

2018年8月26日日曜日

AngularでChart.jsを使った時の「Failed to create chart: can't acquire context from the given item」に対応する。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

Chart.jsは、『グラフと言えばChart.js』ぐらいに有名なライブラリです。
Abgularで使用する場合、npm install で簡単に取り込む事が出来ます。

インストールは本家のGitHub、 Angularで使う場合はこちらのサイト
に非常に詳しい説明があります。

さて、上記を参考にいざ使用してみると・・・・

ブラウザのコンソールに
Failed to create chart: can't acquire context from the given item
が出る事が分かりました。
グラフ自体は問題なく動いているんですけどね。

で、色々と試行錯誤した結果、問題ある箇所は、先のサイトで言うところの
<div *ngIf="chart">
  <canvas id="canvas">{{ chart }}</canvas>
</div>

である事が分かりました。これを・・・
<div [hidden]="chart === null">
  <canvas id="canvas">{{ chart }}</canvas>
</div>

多分、
[hidden]="!chart"
でも大丈夫だと思います。(と言うか、上記の方が良いかも)

要は、「*ngIf」を使ってしまうと、falseになった時に、レンダリングされないので、
chart.jsから「id="canvas"」という要素が見つけられないのでしょうね。

ちょっとハマったので、
同じようなエラーが出た方は、上記で回避してください。


,

2018年8月22日水曜日

windowやdocumentのイベントをAngularで使う。(HostListener)


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

Angularは、自コンポーネント内の項目についてのイベントは簡単に定義出来ます。

[View側]
<button class="button_close" type="button" (click)="close()">閉じる</button>

[Component側]
  close() {
    // ここに処理を記載
  }

しかし、自コンポーネント以外のイベントを取るとなると、ちょっと工夫が要ります。

例えば、下記のような要素があったとします。

「Company」リンクをクリックすれば、吹き出しが出るのは簡単に実装出来ますが、
『吹き出し以外をクリックしたら、吹き出しを閉じる』はどうやって実装したら良いでしょうか?

こんな時に、「HostListener」を使用します。
その名の通り、HostのイベントをListen出来ます。

import {
  Component,
  ChangeDetectionStrategy,
  OnInit,
  HostListener,
  ElementRef
} from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'move-homepage-header',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: './homepage-header.component.html'
})
export class HompageHeaderComponent implements OnInit {

  isShownCompanyPopUp = false;

  constructor(
    private eRef: ElementRef,
    private router: Router
  ) {}

  ngOnInit() {}

  @HostListener('document:click', ['$event'])
  onClickOut(event) {
    if (!this.eRef.nativeElement.contains(event.target)) {
      this.isShownCompanyPopUp = false;
    }
  }

  showCompanyPopup() {
    this.isShownCompanyPopUp = !this.isShownCompanyPopUp;
  }

  linkCompanyInfo() {
   this.isShownCompanyPopUp = false;
    this.router.navigateByUrl('/home/companyinfo');
  }

  linkCompanyMap() {
   this.isShownCompanyPopUp = false;
    this.router.navigateByUrl('/home/companymap');
  }

  linkPrivacyPolicy() {
   this.isShownCompanyPopUp = false;
    this.router.navigateByUrl('/home/privacypolicy');
  }
}

HostListenerのimportは忘れないように記載して下さい。
さて、肝心の部分を抜粋すると・・・・
  @HostListener('document:click', ['$event'])
  onClickOut(event) {
    if (!this.eRef.nativeElement.contains(event.target)) {
      this.isShownCompanyPopUp = false;
    }
  }

今回は、「documentのclickイベント」を使用しています。
ただ、これだと、吹き出しの中のクリックイベントまで対象になってしまうので、
自コンポーネント内は除外し、『自コンポーネント内以外をクリック』のイベントを取る事を実現しています。

いかがでしょうか?
この方法で、windowのresizeイベントも取れると思います。


2018年8月20日月曜日

タブの選択状態をAngularで簡単に実装する。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

画面上のタブに選択状態を表示する・・・下図のような感じの事をやりたい時があります。


Angularなので、Component側でフラグ(変数)を持って、それをView側で判断・・・という事を思い付きますが、もっと簡単な方法があります。

    <div class="header-nav">
      <ul class="header-nav-tabs">
        <li class="nav-tab" routerLinkActive="nav-tab_active"><a class="nav-link" routerLink="/home/test1">テストタブ1</a></li>
        <li class="nav-tab" routerLinkActive="nav-tab_active"><a class="nav-link" routerLink="/home/test2">テストタブ2</a></li>
      </ul>
    </div>

上記のように「routerLinkActive」と「routerLink」の組み合わせで実現出来ます。

routerLink」は該当のhtml要素(今回の場合は「a」タグ)をクリックした際の遷移先を指定します。

routerLinkActive」は、『現在表示している画面(URL)が「routerLink」で指定されているものと一致した場合、指定したクラスを適用する』
という動きをします。

今回の場合は、「nav-tab_active」というCSSクラスに選択状態のスタイルを記述すれば良いわけです。

これでViewでの「*ngIf」地獄から少しは解放されます。


2018年8月6日月曜日

Xcodeでよく使うキーボードショートカット一覧


オフィス狛 技術部 CTOの Taka-yamです。

Xcodeを使用していると複数画面でコードを表示したり、
画面やメニュー間を移動すること多いと思いますが、
その時にキーボードショートカットを知っているとだいぶ時間短縮になり、
作業が楽になります。(と個人的には思っています。)


今回は普段よく使いそうなキーボードショートカットをまとめてみました。

パッと見られるように画像にして印刷できるようにしています。

チートシート的な役割としてお役に立てれば幸いです。

ショートカットを駆使してトラックパッドレス、マウスレスなXcodeライフを!

2018年8月1日水曜日

CSSで背景画像のみぼかして表示したりする際のメモ。

こんにちは、オフィス狛 デザイン部のSatoです。

iOSのパスコード入力時やWebサイトの背景などでよく見る「背景画像が全体的に表示されていてぼかしがかかっている」状態をCSSで再現したかった際にうまくいかなかったりした所があったのでここに記載しておきます。

最初、画像をcssでぼかす事が「filterという画像の見た目を変えることができるクラスで実装できたはず」という知識はぼんやりあったのでとりあえず親要素に「filter: blur(5px);」を指定してみました。
予想はできていましたが、囲った要素全部にぼかしがかかってるし、なぜか画面の端に滲みが出てかっこ悪くなってしまいました。
これが最初の状態です。中央の白い丸の中は完全に読めなくなっていますね……。


調べた所、全体的にぼかしがかかるのも白い滲みもリストの最初に記号を置いたりする時によく使う「::before」という擬似要素で解決できるそうです。
参考にさせて頂いたサイト
背景を画面いっぱいに表示するためのclassで、参考サイトに記載されている背景を綺麗にぼかすためのCSSを囲ってみた所うまくいきました。


背景を画面いっぱいに表示するための部分とぼかすための部分を分けて指定しないと、画像が表示されている部分のみで画面の高さを計算してしまうようで、フッターの部分が下がってしまいスクロールしないと見えなくなってしまうので気をつけてください。