20190827のJavaScriptに関する記事は17件です。

[JS]文字列を複数行に分けて記述

"AAAAAAAAAA\
 BBBBBBBBBBB\
 CCCCCCCCCCC"

\
コレで分ける。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者によるJavaScriptでストップウォッチを作るための学習

ストップウォッチを作ります。
htmlの中身は

  <div id="timer">00:00:000</div>
  <button id="start">Start</button>
  <button id="stop">Stop</button>
  <button id="reset">Reset</button>

と、こんな感じにタイマー部分とそれを操作するボタンを配置。

まずは個々のボタンが動くようにする。

main.js
{
  const timer = document.getElementById('timer');
  const start = document.getElementById('start');
  const stop = document.getElementById('stop');
  const reset = document.getElementById('reset');

  let startTime;
  let timeoutId;

  function countUp() {
    const d = new Date(Date.now() - startTime);
    const m = String(d.getMinutes()).padStart(2, '0');
    const s = String(d.getSeconds()).padStart(2, '0');
    const ms = String(d.getMilliseconds()).padStart(3, '0');
    timer.textContent = `${m}:${s}.${ms}`;

    timeoutId = setTimeout(() => {
      countUp();
    }, 10);
  }

  start.addEventListener('click', () => {
    startTime = Date.now();
    countUp();
  });

  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
  });

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
  });
}

ただしこれだと一旦ストップしてから再スタートすると、00:00:000から始まってしまう。これを止めた時点から再スタートさせたい。
つまりストップした時点の経過時間を保持し、それを足してから再スタートさせれば良い。

経過時間をelapsedTimeと宣言し、0を入れておく(そうすることで最初のスタート時には影響されないようにする)

  let startTime;
  let timeoutId;
  let elapsedTime = 0; // タイマーが走っていた時間 === 経過時間



ストップした時点での経過時間はDate.now() - startTimeで計算してelapsedTimeに入れる。

  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
    elapsedTime = Date.now() - startTime; // ストップした時点での経過時間
  });



次にスタート時に経過時間を加える。

  const d = new Date(Date.now() - startTime + elapsedTime);

ただ、これでは、elapsedTimeが直近の経過時間しか保持していないため、ストップ・スタートを繰り返すと時間が巻き戻ってしまうという問題がある。
従って

    elapsedTime += Date.now() - startTime; // ストップした時点での経過時間

のようにして、今までの経過時間を積み重ねるようにすれば良い。

これで良しと思いきや、リセットを押して再スタートした際は、前回ストップした状態から始まってしまうので、

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
    elapsedTime = 0; // 経過時間のリセット
  });

として、経過時間もリセットすることを忘れないようにする。

※ここで一旦締め

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者によるJavaScriptでストップウォッチを作るための学習 その1

ストップウォッチの枠組みを作る

タイマー部分とStart、Stop、Resetボタンを用意し、ストップウォッチをつくります。

htmlの中身は

  <div id="timer">00:00.000</div>
  <button id="start">Start</button>
  <button id="stop">Stop</button>
  <button id="reset">Reset</button>

と、こんな感じにタイマー部分とそれを操作するボタンを配置。

まずは個々のボタンが動くようにする。

{
  const timer = document.getElementById('timer');
  const start = document.getElementById('start');
  const stop = document.getElementById('stop');
  const reset = document.getElementById('reset');

  let startTime;
  let timeoutId;

  function countUp() {
    const d = new Date(Date.now() - startTime);
    const m = String(d.getMinutes()).padStart(2, '0');
    const s = String(d.getSeconds()).padStart(2, '0');
    const ms = String(d.getMilliseconds()).padStart(3, '0');
    timer.textContent = `${m}:${s}.${ms}`;

    timeoutId = setTimeout(() => {
      countUp();
    }, 10);
  }

  start.addEventListener('click', () => {
    startTime = Date.now();
    countUp();
  });

  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
  });

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
  });
}

ざっと大枠だけ用意するとこうなります。

問題点を解決する

ただしこれだと一旦ストップしてから再スタートすると、00:00:000から始まってしまう。これを止めた時点から再スタートさせたい。
つまりストップした時点の経過時間を保持し、それを足してから再スタートさせれば良い。

経過時間をelapsedTimeと宣言し、0を入れておく(そうすることで最初のスタート時には影響されないようにする)

  let startTime;
  let timeoutId;
  let elapsedTime = 0; // タイマーが走っていた時間 === 経過時間



ストップした時点での経過時間はDate.now() - startTimeで計算してelapsedTimeに入れる。

  stop.addEventListener('click', () => {
    clearTimeout(timeoutId);
    elapsedTime = Date.now() - startTime; // ストップした時点での経過時間
  });



次にスタート時に経過時間を加える。

  const d = new Date(Date.now() - startTime + elapsedTime);

ただ、これでは、elapsedTimeが直近の経過時間しか保持していないため、ストップ・スタートを繰り返すと時間が巻き戻ってしまうという問題がある。
従って

    elapsedTime += Date.now() - startTime; // ストップした時点での経過時間

のようにして、今までの経過時間を積み重ねるようにすれば良い。

これで良しと思いきや、リセットを押して再スタートした際は、前回ストップした状態から始まってしまうので、

  reset.addEventListener('click', () => {
    timer.textContent = '00:00.000';
    elapsedTime = 0; // 経過時間のリセット
  });

として、経過時間もリセットすることを忘れないようにする。

通常の操作以外で発生する問題点を解決する

ストップウォッチとしては動くのですが、いくつかの問題点を抱えたままです。

1.スタートを複数回押した後だと、一回ストップを押しても止まらない
2.ストップを複数回押した後だと、正しい秒数から再開されない

これらは主に、各ボタンを押すごとにstartTimeやelapsedTimeが多重起動してしまうことが原因です。

それらの解決方法は、必要のないボタンは押させないが良いでしょう。フォールトアボイダンスというやつですね。

ボタンの状態を管理する

必要のないボタンを押させない状態は.disabled = true;と設定します。

従って、各状態ごとの状況は

Start Stop Reset
開始時(Initual) false true true
カウント中(Running) true false true
停止時(Stopped) false true false

※true = 非表示 / false = 表示

となります。

これを設定するのは

  function setButtonStateInitial() {
    start.disabled = false;
    stop.disabled = true;
    reset.disabled = true;
  }
  function setButtonStateRunning() {
    start.disabled = true;
    stop.disabled = false;
    reset.disabled = true;

  }
  function setButtonStateStopped() {
    start.disabled = false;
    stop.disabled = true;
    reset.disabled = false;

  }

  setButtonStateInitial(); //初期設定

とし、各ボタンをクリックしたときの関数に、これらの状態へ移行するようにする。

  start.addEventListener('click', () => {
    setButtonStateRunning(); // Runningへ以降
    startTime = Date.now();
    countUp();
  });
  stop.addEventListener('click', () => {
    setButtonStateStopped(); // Stoppedへ以降
    clearTimeout(timeoutId);
    elapsedTime += Date.now() - startTime;
   console.log(elapsedTime);
  });
  reset.addEventListener('click', () => {
    setButtonStateInitial(); // Initualへ以降
    timer.textContent = '00:00.000';
    elapsedTime = 0;
  });

これで操作そのものの問題は概ね解決できたと思います。

続きは装飾部分について取り組みます。その2はこちら https://qiita.com/amanomunt/items/b667aaea307f1df6b104

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【lightbox2】disableScrolling を true にしても、スマホでスクロールできてしまう問題【jQuery】

前回、こんなこと があり、2.10.0 で試しています。

lightbox2 のオプションには disableScrolling があり、true にすると Litebox が開いてる間はスクロールできなくなります。

オプションの参考:簡単に画像のポップアップ!「Lightbox」の実装方法

しかし、true にしても、スマホではスクロールできるバグ?があります。

htmlbody タグに overflow: hidden を指定するとスクロールできなくなります。

ただし、これはPCのみでスマホではスクロールできてしまいます。

そのため、JavaScriptで制御する必要があります。

preventDefault(); を使うスクロールを無効化できましたが、新しいブラウザでは効かないようです。

参考:スクロール禁止が overflow:hidden や preventDefault(); でできないときの対処法

新しいブラウザで preventDefault() を使いたいときは、passive:false にする必要があります。

具体的に言うと addEventListener の第3引数に {passive: false} を指定します。

スクロール禁止・再開を関数化したのが下記です。

function scroll_control(event) {
    event.preventDefault();
}
function no_scroll(){
    document.addEventListener("mousewheel", scroll_control, {passive: false});
    document.addEventListener("touchmove", scroll_control, {passive: false});
}
function return_scroll(){
    document.removeEventListener("mousewheel", scroll_control, {passive: false});
    document.removeEventListener('touchmove', scroll_control, {passive: false});
}

引用元: マウスによるスクロールやスマホのスワイプを制御するjs(passive: false)

no_scroll() を呼び出せばスクロールが禁止され、return_scroll() を呼び出せばスクロール禁止してたのを再開できます。

これらを、litebox.js(v2.10.0) に追記します。

追加箇所の抜粋です。

litebox.js(最初に関数を記述)
/*!
 * Lightbox v2.10.0
 * by Lokesh Dhakar
 *
 * More info:
 * http://lokeshdhakar.com/projects/lightbox2/
 *
 * Copyright 2007, 2018 Lokesh Dhakar
 * Released under the MIT license
 * https://github.com/lokesh/lightbox2/blob/master/LICENSE
 *
 * @preserve
 */

// scroll control
function scroll_control(event) {
    event.preventDefault();
}
function no_scroll(){
    document.addEventListener("mousewheel", scroll_control, {passive: false});
    document.addEventListener("touchmove", scroll_control, {passive: false});
}
function return_scroll(){
    document.removeEventListener("mousewheel", scroll_control, {passive: false});
    document.removeEventListener('touchmove', scroll_control, {passive: false});
}

litebox.js(ライトボックスがスタートするときにno_scroll()を実行)
  // Show overlay and lightbox. If the image is part of a set, add siblings to album array.
  Lightbox.prototype.start = function($link) {

    no_scroll();    // この1行を追記しました。

    var self    = this;
    var $window = $(window);

    $window.on('resize', $.proxy(this.sizeOverlay, this));

    $('select, object, embed').css({
      visibility: 'hidden'
    });

    this.sizeOverlay();

    this.album = [];
    var imageNumber = 0;

    function addToAlbum($link) {
      self.album.push({
        alt: $link.attr('data-alt'),
        link: $link.attr('href'),
        title: $link.attr('data-title') || $link.attr('title')
      });
    }
litebox.js(ライトボックスが終了するときにreturn_scroll()を実行)
  // Closing time. :-(
  Lightbox.prototype.end = function() {

    return_scroll();    // この1行を追記しました。

    this.disableKeyboardNav();
    $(window).off('resize', this.sizeOverlay);
    this.$lightbox.fadeOut(this.options.fadeDuration);
    this.$overlay.fadeOut(this.options.fadeDuration);
    $('select, object, embed').css({
      visibility: 'visible'
    });
    if (this.options.disableScrolling) {
      $('html').removeClass('lb-disable-scrolling');
    }
  };
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsとCSSアニメーションでラーメンタイマーを作る + Firebaseで簡単公開

学びたてだけどVue.js + CSSアニメーション + 絵を組み合わせて作ってみたい!
という事でシンプルなカップラーメンのタイマーを作ってみました。

基本的なVue.jsで始めたばかりの方でも比較的読み進めやすいと思います。
話題のFirebaseで無料公開もとても簡単だったので方法をまとめました。

? ラーメンタイマー

・アプリURL
https://cupramen-timer.firebaseapp.com/
・GitHub - ソースコード
https://github.com/aocattleya/Ramen_Timer

(いいねやスター貰えるととても喜びます!)
 

アプリの内容

使用している物 説明
HTML, CSS animationプロパティを使用
Vue.js JavaScriptフレームワーク
Firebase 無料枠でアプリを公開する
--- ---
SweetAlert アラートを簡単にデザインするライブラリ
GoogleFonts フォントの変更
FireAlpaca ペイントツール(無料)

 
3分 or 5分のボタンをホバーするとキャラクターが左右に振り向きます。
時間を選びクリックするとカウントダウンタイマーが使える簡単な内容です。
レスポンシブデザイン(スマホ)にも対応しています。※左右の振り向きはしない

キャラクターデザイン

まず一番目立つキャラクター
自分は元々漫画家のアシスタントをしていた時期などがあり、
描いた物をアプリに組み合わせてみたかったので描き描き。

レイヤーといって何枚もの板が重なっているように描かれています。
なので例えば手を消すと下に隠れている髪が出てきます。
これによって一枚描いたら背景などが簡単に変更でき、左右反転させて手を描けば2枚完成。

※猫の方が万人受けする。名前募集中!

こちらに原寸サイズ画像&レイヤーファイルを公開しています。
illustration-Original_Characters(GitHub)
 

? コードの解説

それぞれ分けて解説していきます。
コードは分かりやすいように関係ない部分を大幅に省略して書いてます。

 

・キャラクターを左右に振り向かせる

1行目、v-bind:class=""によってclassを「右顔CSS」⇔「左顔CSS」と書き替えており、
きっかけは、それぞれの3分と5分ボタンにあるv-on:mouseover=""

index.html
<!-- キャラクター -->
<img v-bind:class="{ right_face: isRight, left_face: isLeft }" />
  <div class="pick-button">
    <!-- 3分ボタン -->
    <input type="image" src="img/3min.png" v-on:mouseover="rotate_left" />
    <!-- 5分ボタン -->
    <input type="image" src="img/5min.png" v-on:mouseover="rotate_right" />
  </div>
</div>

 
JavaScript側では下記のようにボタンをホバーした時に、
「true」⇔「false」で切り替わる処理を書いています。

main.js
const vm = new Vue({
  el: "#app",
  data: {
    isLeft: false,
    isRight: true,
  },
  methods: {
    rotate_left: function() {
      this.isLeft = true;
      this.isRight = false;
    },
    rotate_right: function() {
      this.isLeft = false;
      this.isRight = true;
    }
  }
});

 
右顔のCSSアニメーション

style.css
.right_face {
  border-radius: 50%;
  background-image: url(../img/button_right.png);
  animation: anime 0.4s linear 2;
}
@keyframes anime {
  100% {
    transform: rotateY(360deg);
  }
}

border-radius: 50%で画像を丸くする。
・そしてanimationプロパティ、長さなどを設定でき@keyframesで動きを付けます。
 上記は100%終了時までにY軸に360度回転としています。
 
 
 

・ボタン選択で画面の切り替え

ページは変わっていません。
Vue.jsで最初の画面を非表示にし、非表示になっていたタイマー画面を表示させています。

3分 or 5分ボタンを押すとv-on:click="show = !show"によって、
<div v-show="!show"><div v-show="show">と画面表示が切り替わります。

index.html
<!-- 3分 or 5分ボタン選択画面 -->
<div v-show="!show">
  <input type="image" src="img/3min.png" v-on:click="show = !show" />
  <input type="image" src="img/5min.png" v-on:click="show = !show" />
</div>

<!-- タイマー画面 -->
<div v-show="show">
  <span id="minutes">{{ minutes }}</span>
  <span id="middle">:</span>
  <span id="seconds">{{ seconds }}</span>
  <!-- 省略 -->
</div>

 
 

・タイマーの実装

timre3.gif

index.html
<!-- 3分 or 5分ボタン -->
<input type="image" src="img/3min.png" v-on:click="show = !show; threeMin()" />
<input type="image" src="img/5min.png" v-on:click="show = !show; fiveMin()" />

3分 or 5分ボタンをクリックした時に、
v-on:click="threeMin()"又はv-on:click="fiveMin()"が実行され、
タイマー画面でカウントする時間を3:00 or 5:00にします。
 

index.html
<!-- タイマー -->
<div class="timer">
  <span id="minutes">{{ minutes }}</span>
  <span id="middle">:</span>
  <span id="seconds">{{ seconds }}</span>
</div>
<div id="buttons">
  <!-- スタート -->
  <input type="image" src="img/start.png" v-on:click="startTimer" v-if="!timer" />
  <!-- ストップ -->
  <input type="image" src="img/stop.png" v-on:click="stopTimer" v-if="timer" />
  <!-- リセット -->
  <input type="image" src="img/reset.png" v-on:click="resetTimer" v-if="resetButton" />
</div>

タイマーのカウントは、HTMLの{{ minutes }} : {{ seconds }}
この部分がVue.jsの処理でタイマーのように変更されていきます。
 

main.js
const vm = new Vue({
  el: "#app",
  data: {
    timer: null,
    pickTime: null,
    totalTime: null,
    resetButton: false
  },
  methods: {
    // 3分 or 5分ボタン
    threeMin: function() {
      this.pickTime = 3 * 60;
      this.totalTime = this.pickTime;
    },
    fiveMin: function() {
      this.pickTime = 5 * 60;
      this.totalTime = this.pickTime;
    },
    // スタート
    startTimer: function() {
      this.timer = setInterval(() => this.countdown(), 1000);
      this.resetButton = true;
    },
    // ストップ
    stopTimer: function() {
      clearInterval(this.timer);
      this.timer = null;
      this.resetButton = true;
    },
    // リセット
    resetTimer: function() {
      this.totalTime = this.pickTime;
      clearInterval(this.timer);
      this.timer = null;
      this.resetButton = false;
    },
    // 秒が一桁の場合0を追加
    padTime: function(time) {
      return (time < 10 ? "0" : "") + time;
    },
    // カウントダウン
    countdown: function() {
      if (this.totalTime >= 1) {
        this.totalTime--;
      } else {
        this.totalTime = 0;
        this.resetTimer();
        swal("Complete!!", "", "success");
      }
    }
  },
  computed: {
    // タイマーの数値
    minutes: function() {
      const minutes = Math.floor(this.totalTime / 60);
      return minutes;
    },
    seconds: function() {
      const seconds = this.totalTime - this.minutes * 60;
      return this.padTime(seconds);
    }
  }
});

computed:の部分がHTMLのタイマー{{ }}に表示され、ボタンで各methods:が働き、
スタートを押すとsetInterval()により、一秒ごとにcountdownが実行されます。
 
 
 

・アラートデザイン『SweetAlert』

sweet.png

簡単にアラートがデザイン出来るライブラリ
ブラウザからCDN経由で読み込みができます。

index.html
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
main.js
swal("Complete!!", "", "success");

これだけ、凄い!
このアラートはスマホでも同じデザインで表示されます。

その他の使い方は下記のページが分かりやすいです。
- SweetAlertバージョン2を使ったデモ
 
 
 

? Firebaseで公開(無料)

Firebase - Google
 
最近とても話題のFirebaseで、作成したアプリを無料で公開。
データベースなど複雑に使う事も可能ですが、今回は簡単に無料で公開してみます。

下記はQiita用にtestプロジェクトで進めていますが、任意の名前にしてください。

1、ログイン
Firebaseのページを開いてログイン

2、プロジェクトの作成

プロジェクト名を記入します。
IDの部分はURLになりますので好みのIDに書き変えましょう。

Googleアナリティクスの設定を聞かれます。
今回は、使用しないで進めます。

3、フォルダの設定

Desktopにプロジェクト名と同じフォルダを作成します。
中にpublicという名前でフォルダを作成して公開したいコードを入れます。

4、Node.jsのインストール
まだ入ってない方はインストールしてください。
すぐ終わります。

Node.js

5、firebase-toolsをインストール

npm install -g firebase-tools

6、ログイン

firebase login

利用状況のデータを送っても良いか聞かれたら任意でY/n
次にGoogleログイン画面が表示されるので、アカウントを選び進めます。

7、デプロイ設定

cd Desktop/test

プロジェクトのフォルダに移動します。

firebase init

下記のような画面が表示されます。

◉ Hosting: Configure and deploy Firebase Hosting sites

Hostingをスペースで選択してからEnterを押します。
※スペースで選択していなとエラーとなる。

? Please select an option: 

Don't set up a default projectを選択してEnter

? What do you want to use as your public directory?(public)

そのままEnter(デフォルトのpublicとなる)

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N) 

そのままEnter(デフォルトでN)

? File public/index.html already exists. Overwrite? (y/N) 

index.htmlを上書きしていいか聞いてくるのでN(そのままEnterでN)


上手くいきました。

8、公開する

firebase use --add

上記でEnter

? Which project do you want to add?
> test-71a0e

作成したプロジェクトを選択します。

? What alias do you want to use for this project? (e.g. staging)

名前は任意です。今回はstagingとしました。

firebase deploy

完了です!

9、Hosting URL:をブラウザでアクセス

こうして完成、簡単にFirebaseでの公開も出来ました。使ってね!

・ラーメンタイマー
https://cupramen-timer.firebaseapp.com/
・ソースコード - GitHub
https://github.com/aocattleya/Ramen_Timer

 
 

終わりに

Vue.jsで何か作ってみたい、CSSアニメーションと絵も組み合わせたい!

そんな考えから作ってみたアプリでシンプルに見えて苦戦もありました。
しかし言語を学習してるだけと違い、新たな発見と理解はとても多かったです。
基本的な構文でここまで作れて達成感も大きかったのでやって凄く良かったと思います。

次はさらにレベルを上げて作ってみたいですね!
最後まで読んでくれてありがとうございました。
 

参考

【CSS3】@keyframes と animation 関連のまとめ
SweetAlertバージョン2を使ったデモ
Firebaseを用いて5分でセキュアなWebサイトを公開する

リンク

:octocat: GitHub
https://github.com/aocattleya
? Twitter
https://twitter.com/aocattleya
? Qiita
https://qiita.com/aocattleya

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsとCSSアニメーションでラーメンタイマーを作った + Firebaseで簡単公開

Vue.jsを学び始めてCSSアニメーションも触ってみたいという事で簡単なアプリを作ってみました。
基本的なVue.jsの機能で始めたばかりの方でも比較的に読み進めやすいかと思います。
話題のFirebaseでの無料公開もとても簡単なので方法をまとめました。

? ラーメンタイマー

timre1.gif
・アプリURL
https://cupramen-timer.firebaseapp.com/
・GitHub - ソースコード
https://github.com/aocattleya/Ramen_Timer

(いいねやスター貰えるととても喜びます!)
 

アプリの内容

使用している物 説明
HTML, CSS animationプロパティを使用
Vue.js JavaScriptフレームワーク
Firebase 無料枠でアプリを公開する
--- ---
SweetAlert アラートを簡単にデザインするライブラリ
GoogleFonts フォントの変更
FireAlpaca ペイントツール(無料)

 
3分 or 5分のボタンをホバーするとキャラクターが左右に振り向きます。
時間を選びクリックするとカウントダウンタイマーが使える簡単な内容です。
レスポンシブデザイン(スマホ)にも対応しています。※左右の振り向きはしない

キャラクターデザイン

まず一番目立つキャラクター
自分は元々漫画家のアシスタントをしていた時期などがあり、
描いた物をアプリに組み合わせてみたかったので描き描き。

レイヤーといって何枚もの板が重なっている感じで描かれています。
なので例えば手を消すと下に隠れている髪が出てきます。
これによって一枚描いたら背景などが簡単に変更でき、左右反転させて手を描けば2枚完成。

※猫の方が万人受けする。名前募集中!

こちらに原寸サイズ画像&レイヤーファイルを公開しています。
illustration-Original_Characters(GitHub)
 

? コードの解説

それぞれ分けて解説していきます。
コードは分かりやすいように関係ない部分を大幅に省略して書いてます。

 

・キャラクターを左右に振り向かせる

1行目、v-bind:class=""によってclassを「右顔CSS」⇔「左顔CSS」と書き替えており、
きっかけは、それぞれの3分と5分ボタンにあるv-on:mouseover=""

index.html
<!-- キャラクター -->
<img v-bind:class="{ right_face: isRight, left_face: isLeft }" />
  <div class="pick-button">
    <!-- 3分ボタン -->
    <input type="image" src="img/3min.png" v-on:mouseover="rotate_left" />
    <!-- 5分ボタン -->
    <input type="image" src="img/5min.png" v-on:mouseover="rotate_right" />
  </div>
</div>

 
JavaScript側では下記のようにボタンをホバーした時に、
「true」⇔「false」で切り替わる処理を書いています。

main.js
const vm = new Vue({
  el: "#app",
  data: {
    isLeft: false,
    isRight: true,
  },
  methods: {
    rotate_left: function() {
      this.isLeft = true;
      this.isRight = false;
    },
    rotate_right: function() {
      this.isLeft = false;
      this.isRight = true;
    }
  }
});

 
右顔のCSSアニメーション

style.css
.right_face {
  border-radius: 50%;
  background-image: url(../img/button_right.png);
  animation: anime 0.4s linear 2;
}
@keyframes anime {
  100% {
    transform: rotateY(360deg);
  }
}

border-radius: 50%で画像を丸くする。
・そしてanimationプロパティ、長さなどを設定でき@keyframesで動きを付けます。
 上記は100%終了時までにY軸に360度回転としています。
 
 
 

・ボタン選択で画面の切り替え

ページは変わっていません。
Vue.jsで最初の画面を非表示にし、非表示になっていたタイマー画面を表示させています。

3分 or 5分ボタンを押すとv-on:click="show = !show"によって、
<div v-show="!show"><div v-show="show">と画面表示が切り替わります。

index.html
<!-- 3分 or 5分ボタン選択画面 -->
<div v-show="!show">
  <input type="image" src="img/3min.png" v-on:click="show = !show" />
  <input type="image" src="img/5min.png" v-on:click="show = !show" />
</div>

<!-- タイマー画面 -->
<div v-show="show">
  <span id="minutes">{{ minutes }}</span>
  <span id="middle">:</span>
  <span id="seconds">{{ seconds }}</span>
  <!-- 省略 -->
</div>

 
 

・タイマーの実装

timre3.gif

index.html
<!-- 3分 or 5分ボタン -->
<input type="image" src="img/3min.png" v-on:click="show = !show; threeMin()" />
<input type="image" src="img/5min.png" v-on:click="show = !show; fiveMin()" />

3分 or 5分ボタンをクリックした時に、
v-on:click="threeMin()"又はv-on:click="fiveMin()"が実行され、
タイマー画面でカウントする時間を3:00 or 5:00にします。
 

index.html
<!-- タイマー -->
<div class="timer">
  <span id="minutes">{{ minutes }}</span>
  <span id="middle">:</span>
  <span id="seconds">{{ seconds }}</span>
</div>
<div id="buttons">
  <!-- スタート -->
  <input type="image" src="img/start.png" v-on:click="startTimer" v-if="!timer" />
  <!-- ストップ -->
  <input type="image" src="img/stop.png" v-on:click="stopTimer" v-if="timer" />
  <!-- リセット -->
  <input type="image" src="img/reset.png" v-on:click="resetTimer" v-if="resetButton" />
</div>

タイマーのカウントは、HTMLの{{ minutes }} : {{ seconds }}
この部分がVue.jsの処理でタイマーのように変更されていきます。
 

main.js
const vm = new Vue({
  el: "#app",
  data: {
    timer: null,
    pickTime: null,
    totalTime: null,
    resetButton: false
  },
  methods: {
    // 3分 or 5分ボタン
    threeMin: function() {
      this.pickTime = 3 * 60;
      this.totalTime = this.pickTime;
    },
    fiveMin: function() {
      this.pickTime = 5 * 60;
      this.totalTime = this.pickTime;
    },
    // スタート
    startTimer: function() {
      this.timer = setInterval(() => this.countdown(), 1000);
      this.resetButton = true;
    },
    // ストップ
    stopTimer: function() {
      clearInterval(this.timer);
      this.timer = null;
      this.resetButton = true;
    },
    // リセット
    resetTimer: function() {
      this.totalTime = this.pickTime;
      clearInterval(this.timer);
      this.timer = null;
      this.resetButton = false;
    },
    // 秒が一桁の場合0を追加
    padTime: function(time) {
      return (time < 10 ? "0" : "") + time;
    },
    // カウントダウン
    countdown: function() {
      if (this.totalTime >= 1) {
        this.totalTime--;
      } else {
        this.totalTime = 0;
        this.resetTimer();
        swal("Complete!!", "", "success");
      }
    }
  },
  computed: {
    // タイマーの数値
    minutes: function() {
      const minutes = Math.floor(this.totalTime / 60);
      return minutes;
    },
    seconds: function() {
      const seconds = this.totalTime - this.minutes * 60;
      return this.padTime(seconds);
    }
  }
});

computed:の部分がHTMLのタイマー{{ }}に表示され、ボタンで各methods:が働き、
スタートを押すとsetInterval()により、一秒ごとにcountdownが実行されます。
 
 
 

・アラートデザイン『SweetAlert』

sweet.png

簡単にアラートがデザイン出来るライブラリ
ブラウザからCDN経由で読み込みができます。

index.html
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
main.js
swal("Complete!!", "", "success");

これだけ、凄い!
このアラートはスマホでも同じデザインで表示されます。

その他の使い方は下記のページが分かりやすいです。
- SweetAlertバージョン2を使ったデモ
 
 
 

? Firebaseで公開(無料)

Firebase - Google
 
最近とても話題のFirebaseで、作成したアプリを無料で公開。
データベースなど複雑に使う事も可能ですが、今回は簡単に無料で公開してみます。

下記はQiita用にtestプロジェクトで進めていますが、任意の名前にしてください。

1、ログイン
Firebaseのページを開いてログイン

2、プロジェクトの作成

プロジェクト名を記入します。
IDの部分はURLになりますので好みのIDに書き変えましょう。

Googleアナリティクスの設定を聞かれます。
今回は、使用しないで進めます。

3、フォルダの設定

Desktopにプロジェクト名と同じフォルダを作成します。
中にpublicという名前でフォルダを作成して公開したいコードを入れます。

4、Node.jsのインストール
まだ入ってない方はインストールしてください。
すぐ終わります。

Node.js

5、firebase-toolsをインストール

npm install -g firebase-tools

6、ログイン

firebase login

利用状況のデータを送っても良いか聞かれたら任意でY/n
次にGoogleログイン画面が表示されるので、アカウントを選び進めます。

6、デプロイ設定

cd Desktop/test

プロジェクトのフォルダに移動します。

firebase init

下記のような画面が表示されます。

◉ Hosting: Configure and deploy Firebase Hosting sites

Hostingをスペースで選択してからEnterを押します。
※スペースで選択していなとエラーとなる。

? Please select an option: 

Don't set up a default projectを選択してEnter

? What do you want to use as your public directory?(public)

そのままEnter(デフォルトのpublicとなる)

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N) 

そのままEnter(デフォルトでN)

? File public/index.html already exists. Overwrite? (y/N) 

index.htmlを上書きしていいか聞いてくるのでN(そのままEnterでN)


上手くいきました。

・公開する

firebase use --add

上記でEnter

? Which project do you want to add?
> test-71a0e

作成したプロジェクトを選択します。

? What alias do you want to use for this project? (e.g. staging)

名前は任意です。今回はstagingとしました。

firebase deploy

完了です!

Hosting URL:をブラウザでアクセス

こうして完成、簡単にFirebaseでの公開も出来ました。使ってね!

・ラーメンタイマー
https://cupramen-timer.firebaseapp.com/
・ソースコード - GitHub
https://github.com/aocattleya/Ramen_Timer

 
 

終わりに

まだVue.js学びたてだけど何か作ってみたい
CSSアニメーションも使って絵も描いて組み合わせたい!

そんな考えから簡単に作ってみたアプリでシンプルに見えて苦戦もありました。
しかし言語を学習してるだけと違い、新たな発見と理解はとても多かったです。
基本的な構文でここまで作れて達成感も大きかったので凄くやって良かったと思います。

次はさらにレベルを上げて作ってみたいですね!
最後まで読んでくれてありがとうございました。
 

参考

【CSS3】@keyframes と animation 関連のまとめ
SweetAlertバージョン2を使ったデモ
Firebaseを用いて5分でセキュアなWebサイトを公開する

リンク

:octocat: GitHub
https://github.com/aocattleya
? Twitter
https://twitter.com/aocattleya
? Qiita
https://qiita.com/aocattleya

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

予約システム pickadate.jsで実装 ~ヘルスケアwebサービスを自分で作る医者の日記~

クリニックの予約サイトを作るために、勉強中

https://qiita.com/Yuta_Fujiwara/items/66af40dcc5ce206933eb
こちらの記事を参考にさせていただいた。

datepicker

公式のドキュメントとにらめっこしていると、
なんとか、実装はできるようなった。

作りたいのは、予約システム

jsからwebサーバーに送る処理の理解が必要
上の記事はajax使っているのね、
なんとか、ググってajaxの基本を1日で習得
vagrantでphpウェブサーバーを立ち上げる方法で実装

$(function() {

    // datepicker表示イベント
    $('#date').pickadate();

    // timepicker表示イベント
    $('#time').pickatime({
        format: 'HH:i', // 24時間表記
        interval: 30,   // 表示間隔
        min: [10,00],   // 予約開始時間
        max: [20,00]    // 予約終了時間
    });

    // 予約ボタン押下イベント
    $('#submit').click(onClickSubmit);

    //予約ボタン押下処理
    function onClickSubmit(){
        $('#submit_result').remove();
        var date = $('#date').val();
        var time = $('#time').val();

        if(date!='' && time !=''){

          $.ajax({
            async: true,
            url: 'http://192.168.33.10:8000/yoyaku_datepicker.php',
            type: "POST",
            dataType: 'json',
            data: {
              'hiduke': date,
              'jikan': time
            }
          }).done(function(data) {
            console.log(data.kekka + "を取得しました。");
          }).fail(function() {
            console.log("処理を失敗しました。");
          });

            //予約完了メッセージ
            $('#result').after('<div id="submit_result" class="section__block section__block--notification"><p><strong>'+date+time+'〜</strong><br>予約受け付けました。</p></div>');

        }else{
            //予約失敗メッセージ
            $('#result').after('<div id="submit_result" class="section__block section__block--notification-red"><p>予約日・予約時間を選択してください。</p></div>');
        }
    }

});
<?php

$hiduke = $_POST['hiduke'];
$jikan = $_POST['jikan'];



if ($hiduke  && $jikan) {
  $datepick['kekka'] = "ご指定の日時";
} else {
  echo false;
}

echo json_encode($datepick);

最終的にはrailsでやりたいのだが、
データベースへの格納を理解できなきゃならない
railsのacctive recordか

ていうか、vagrant のwebサーバーでデータベースの取り扱いはできるのか??

道は長い、、、

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【p5.js】p5.jsでクリエイティブなwebサイトを作る

p5.jsをはじめよう

p5.jsとはビジュアルプログラミング言語ProcessingをJavascriptに移植したライブラリです。

クリエイティブコーディングやVJで用いられるのをよく見かけますが、
この記事では普段のwebサイト制作で使えるようなp5.jsの活用方法をまとめていきます!

p5.jsを仕事で書きたい!
でも実用的でないと書けない!
webサイトで良い感じに組み込んで良い感じの見た目が作れるんだよとアピールして
仕事でp5.jsを書いていきたい全ての人に捧げます

インストール

まずp5.jsをインストールします。
https://p5js.org/get-started/
この記事では詳細を割愛します…!
こちらの公式ドキュメントより直接DLするか、CDNで読み込んでください。

セットアップ

ベーシックなhtmlを用意します。

index.html
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>p5 sample</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
    <script src="sketch.js"></script>
</head>
<body>
</body>
</html>

今回は別途sketch.jsを用意し、以下のようにp5.jsの記述をしていきます。

sketch.js
function setup() {
}

function draw() {
}

p5.jsの基本形

さて、まずはじめにp5.jsの基本の書き方を押さえていきます。

sketch.js
function setup() {
    createCanvas(width, height); // width, heightにcanvasの大きさを記述
}

function draw() {
    // 図形など
}

基本的にp5.jsでは
setup関数でcanvasを生成し、draw関数にcanvasへ描画する図形を書いていきます。
(setup関数はページ読み込み時一回だけ実行、draw関数は1秒に60回ごと実行されます :引用

p5.jsの公式サイトではこんなサンプルが紹介されています。

function setup() {

}

function draw() {
  ellipse(50, 50, 80, 80);
}

ellipseは円を描くコンポーネント。
実行すると以下のようにシンプルな円が描かれます。
スクリーンショット 2019-08-27 15.46.54.png
はい。超簡単。
コード数行で簡単に図形を描くことができました。

p5.js: Get Started

p5.jsでできること

さて、基本形はわかりましたが、実際書いていくにはどんなコンポーネントを使うことができるのでしょうか?
公式ドキュメントに一覧が載っていますが、この記事ではかいつまんで少しだけご紹介します。

2D図形

先ほどの例のような円から四角形、線などが描画できます。

- ellips(x, y, w, h); // 円
- line(): // 線
- rect(x, y, w, h); // 四角形

3D図形

3Dを扱う場合にはsetup関数でcanvasを生成するときにwidth, heightの後にWEBGLとを表記する必要がありますので注意しましょう。


- bod(x, y, z); //直方体
- sphere(radius); // 球
- cylinder(radius, height); // 三角錐

アニメーション

アニメーションで表現の幅を増やすこともできます


- translate(x, y, z); // 3D描画の場合のxyz軸への移動
- rotateX(frameCount * 0.01); // x軸方向の回転

その他にもシェーダーを記述できたり、テクスチャをつけたり、色々なことができます。
公式リファレンス

p5.jsをwebサイトで利用しよう

それではここから発展系!
p5.jsで作ったものをwebサイトに活用してクリエイティブなwebサイトをサクサク作ってみましょう!

この記事ではこんなものを試してみました
1. webサイトの背景
2. カーソルで遊ぶ
3. お絵かき機能をつける

1. webサイトの背景

p5.jsで作った絵をwebサイトの背景に使ってみましょう!

完成イメージ
gif.gif

p5.jsのcanvasをz-index=-1にすることで、背景にクリエイティブな図形を表示させることができます。

cssの設定はこちらの記事が参考になります!
https://qiita.com/ryomeguro/items/02e0f4b40f9cc8d3045e

JSはこちら

sketch.js
 function windowResized() {
            resizeCanvas(windowWidth, windowHeight);
            canvasSetup;
        }
        function setup() {
            canvas = createCanvas(windowWidth, windowHeight, WEBGL);
        }

        function draw() {
            background(255);
            for (var y = 0; y <= 1000; y = y + 500) {
                for (var x = 0; x <= 1000; x = x + 500) {

                    noFill();
                    stroke(255, 147, 206);
                    rotateX(frameCount * 0.01);
                    rotateY(frameCount * 0.01);
                    box(200, 200, 200);
                }
            }
        }

なんだかイケてるIT企業のコーポレートサイトみたいですね。
仕事で超使えそうです。

2. カーソルで遊ぶ

p5.jsでマウスカーソルの表現をちょっとリッチに変えてみましょう!

完成イメージ
gif (1).gif

これは1の背景と同じようにcss側でcanvasのz-indexを一番低くしておき、
また、backgroundの色を黒に設定しておきます。

sketch.js
function windowResized() {
    resizeCanvas(windowWidth, windowHeight);
    canvasSetup;
}
function setup() {
    canvas = createCanvas(windowWidth, windowHeight);
}
function draw() {
    background(0, 30);
    ellipse(mouseX, mouseY, 40, 40);
    fill(230);
    noStroke();
}

setup関数の読み込みが一回に対して、draw関数は基本的に1フレームごとに都度描画されます。
その都度backgroundも描画されていますので
backgroundの色を半透明にすることでマウス追従の図形の色が時間が経つにつれて薄くなる、という表現を可能にしています。

こちらの記事を参考にさせていただきました:
https://www.i-ryo.com/entry/2019/07/21/194243

3. お絵かき機能をつける

マウスやスマホのタッチで絵が描けるお絵かき機能も、p5.jsなら簡単に実装できます。

完成イメージ
スクリーンショット 2019-08-28 12.41.18.png

コードはこちら

sketch.js
function setup() {
    canvas = createCanvas(windowWidth / 2, windowHeight / 3);
    background(8, 91, 26);
}

function touchMoved() {
    smooth();
    stroke(255);
    strokeWeight(4);
    line(mouseX, mouseY, pmouseX, pmouseY);
    return false;
}

function download() {
    var canvas = document.getElementById("defaultCanvas0");
    var link = document.getElementById("DLlink")
    link.href = canvas.toDataURL()

    // document.getElementById("canvasImage").src = canvas.toDataURL()

    link.click()
}

消すボタンは
<a href="javascript:setup()" class="btn">消す</a>
こんな感じでhtmlからもう一度setup関数を呼び出しています。

canvasをpngに変換してダウンロードさせるコードはこちらを参考にさせていただきました!
https://qiita.com/iwaimagic/items/1d16a721b36f04e91aed

まとめ

p5.jsは簡単なことから複雑な描画までを実現できます。

web表現のアイディアのひとつとして、カジュアルに仕事で使っていきたいですね♪

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで実際に動くものを作ってみた_2

はじめに

引き続きJavaScriptの勉強をしました。
今回はブラウザにデータを保持するものを作りたいと考え、会社の研修で使った紙の資料である「行動習慣チェックリスト」をデジタル化してみました。

作ったもの

スクリーンショット (130).png

日付のところに〇△×をセレクトボックスから選択し、1カ月の習慣を記録していきます。
localStrageを用いることで集計したデータはブラウザ上に保持されます。

コードはかなり冗長で汚くなってしまったので今回は省略します。

今回の経験で学んだこと

localStrage

ブラウザにデータを保持する際に使ったもの。
今回は日毎にチェックした値を保存している。
当初はCookieを使用する予定だったが、こちらの方が使いやすそうだったので変更。
localStrageはKeyとValueのセットで使用され、値は文字列で使用される。
以下に簡単な例を載せます。

// Keyに値をセットする場合はsetItemを使用
localStorage.setItem("設定するKey", "Keyに設定するValue");

// Keyの値を取得する場合はgetItemを使用
let a = localStorage.getItem("取得するKey");

// Keyを削除する際はremoveItemを使用
localStorage.removeItem("削除するKey");  

// Sample
// javascriptというKeyに文字列"difficult"を設定する
localStorage.setItem("javascript", "difficult");

// 変数aには文字列"difficult"が設定される
let a = localStorage.getItem("javascript");

insertAdjacentHTML

HTMLの追加時(集計ボタンを押す処理)に使用。
前回使ったinnerHTMLと同じ要領で使用する。
'beforebegin'や'afterbegin'などで挿入する位置を選択できる。

おわりに

当初は日付の部分をカレンダーにしたり、月ごとの結果を別途保存する機能を追加しする予定でしたが、操作が複雑化しそうなため止めました。
毎日の行動チェックであるため極力シンプルな方がいいですよね。

参考サイト

WebStorage API(LocalStorage)を使ってみた

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでおみくじを作ってみた- 勉強のメモ

おみくじアプリの作成過程をまとめて。

目的

ボタンを押したら画像がランダムで出てくるタイプのおみくじを作る。
画像はいらすとやさんからお借りしました。

コード

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Kosugi+Maru&display=swap" rel="stylesheet">
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
    <title>おみくじ</title>
</head>
<body>

    <section>

        <h1>おみくじ</h1>

        <div id="result"><i class="fas fa-question faa-wrench animated"></i></div>

        <div id="btn"><i class="far fa-star fa-spin"></i>占う</div>


    </section>
</body>
</html>
CSS
body{

    font-family: 'Kosugi Maru', sans-serif;
    text-align: center;
}

h1{

    font-size: 30px;

}

#result{

    margin: 0 auto;
    width: 181px;
    height: 400px;
    border: 5px solid black;
    border-radius: 20px;
    font-size: 60px;
    line-height: 400px;
}

#btn{

    font-size: 20px;
    color: #ffffff;
    background: #7ab6ff;
    box-shadow: 0 4px 0#0f7bff;
    border-radius: 20px;
    width: 300px;
    padding: 20px 0;
    margin: 30px auto 0 auto;
    cursor: pointer;

}

#btn:active{
    box-shadow: 0 2px 0 #0f7bff;
}

JavaScript
var img = new Array (
    './images/daikiti.png',
    './images/chukiti.png',
    './images/syouchiti.png',
    './images/kichi.png',
    './images/suekiti.png',
    './images/kyou.png',
    './images/daikyou.png'
);

var button = document.getElementById('btn');

button.addEventListener('click', () =>{

    var random = Math.floor(Math.random() * img.length);
    var result = '<img src =' +img[random]+ '>';

    document.getElementById('result').innerHTML = result;

})

コードの解説

CSS
#btn:active{
    box-shadow: 0 2px 0 #0f7bff;
}

btnをクリックされたときのスタイルをbox-shadowで指定。

JavaScript
var img = new Array (
    './images/daikiti.png',
    './images/chukiti.png',
    './images/syouchiti.png',
    './images/kichi.png',
    './images/suekiti.png',
    './images/kyou.png',
    './images/daikyou.png'
);

変数で画像の配列を作成。

HTML
<div id="btn"><i class="far fa-star fa-spin"></i>占う</div>
JavaScript
var button = document.getElementById('btn');

HTMLのbtnを変数で指定する。

JavaScript
button.addEventListener('click', () =>{

   //クリックされたときの内容を記述

})


btnがクリックされたときの内容を記述する。
ランダムで画像を表示させたいので、Math.random()を使いランダムで配列を出す。

JavaScript
var random = Math.floor(Math.random() * img.length);
    var result = '<img src =' +img[random]+ '>';

変数を使い画像を表示する要素を生成する。

JavaScript
document.getElementById('result').innerHTML = result;

HTMLのresultinnerHTMLを使い画像を表示。

完成

omikuji.gif

参考

いらすとや
ドットインストール

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactのコンポーネントに関する覚書

JSX記法はReact.createElementの糖衣構文という文脈で色々と実験してみた結果

JSXのタグ名は変数名でも可

ユーザー定義のタグ(大文字から始まるもの)は参照できる範囲の識別子なら可能なので、適当な変数に代入してその変数名を使っても良い。
(React.createElementの第一引数に過ぎないので)
ただ、先頭を大文字にしないと独自コンポーネントと認識してくれないのでそこだけは守る必要あり

表示するコンポーネントの動的切替なんかもタグと{}の中から追い出すことも出来る

const Hoge = FugaComponent;

//render内
<Hoge/> //FugaComponentが出力される

const Hoge = someCondition ? FugaComponent : PiyoComponent;

<Hoge/> //someConditionに応じてどちらが表示されるか決まる

JSX記法とReact.createElementは混ぜても使える

以下のような感じ

render () {
 <React.Fragment>
   {React.createElement('div',{},'hoge')}
 </React.Fragment>
}
//<div>hoge</div>になる

JSXのタグで挟まれた要素は、React.createElementの第3引数(children)に渡される
JSX要素とReact.createElementの戻り値は内部的に同じになるなのでこれでもOK。

実務での使いどころはあるのかというと多分ないけれど。

ただ、JSXのタグの子要素はあくまで第3引数渡される値ということを認識しておくと、
軽く条件分岐する時にifではなく三項演算子を使う理由や、
ループを回す際にmapを使う理由辺りにも納得がいきやすい。
無名関数の実行とreturnし忘れ等も減るのではないかと。

まとめ

  • タグ名はあくまで第一引数
  • タグの子要素は第三引数に渡す値 => よって{}内は式でないといけない
  • 内部的にJSXタグとReact.createElementは等価なので混ぜても使える
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

YAML で画面設計書を書いて Markdown で出力する

タイトルの内容をこうやってみましたというレポートです。

経緯

  • 小さめ(画面10未満)・比較的単純なWebアプリ案件の設計書を記述する必要あり
  • 設計書のフォーマット・ファイル形式に指定はなし、ファイル出力の必要もなし
  • 好きにやっていいとの指示

希望

  • Word や Excel で書きたくない
  • テキストベースで書いて、リポジトリ管理したい
  • ソースと配置をなるべく分けたくない
    • ソースはGitLab リポジトリで管理

  • GitLab の Wiki に Markdown で記述する

懸念点

  • Markdown では、画面設計書に必要な以下の内容を記述しにくい
    • 表形式
    • 定まったフォーマット(記述の自由度が高い)

打開策

  • 内容は、YAML で記述する
  • 表形式など表示を見やすくするために、YAML を読み込んで Markdown に変換する

YAML とは

人間が扱いやすい、構造化データ・オブジェクトを記述するためのデータ形式
公式

Swagger Spec の記述形式としても有名ですね。
Swagger Editorみたいな感じで、画面設計書も記述できるといいなーと思ったのが、今回の試みの発端です。

YAML が設計書の記述に合っているところ

  • 階層構造が記述できる
  • データが型を持つ
  • 改行を含んだデータを含めることができ、わかりやすく記述できる
  • JSON Schemaが設定できる

JSON Schema とは?

  • JSONの記述フォーマットを定義したもの
    公式

  • IDEに設定することで、入力補助やバリデーションチェックに利用できる

  • VSCode では、Extension YAML を使うことで、YAML のスキーマとして用いることができる

やったこと

JSON Schema を作成

1. 作成したいYAMLを一部分作成する
画面設計書なので画面要素1つ分の記述とか

2. 1. で作成したYAML を JSON に変換する
Webサービス yaml2json を利用
tQir2RbFy-chrome_2019-08-26_14-06-47.png

3. 2. で作成したJSONを元に、JSON Schema を作成
Webサービス JSON schema.neatを利用
入力した値を元にSchemaのスケルトンを作ってくれる
DlXN-yZ6f-chrome_2019-08-26_14-11-35.png

JSON Schema を VSCodeに設定

  1. Extension YAML を追加する
  2. YAMLのsetting にJSON Schema を設定する
setting.json
{
  "yaml.completion": true,
  "yaml.validate": true,
  "yaml.hover": true,
  "yaml.schemas": {
    "./screen.json": [
      "*.yml",
    ],
  },
  "yaml.format.enable": true,
}

手順は VSCodeで快適に設定ファイルを書く 参照

画面設計書(YAML)を書く

VSCode で YAML をゴリゴリ書いていきます。

  • Ctrl + space で入力補助がでます!(捗る!)
  • Scheme と合わない記述については、エラー表示されます
  • 入力パターンなど、Schema に追加したほうがよい内容は随時追加する → エラーが出るのでつぶしていく、の繰り返しで進めていきます R1sgPKJZt-Code_2019-08-26_14-28-37.png

YAMLをMarkdown に変換する

YAMLを読み込み、テンプレートを埋めて出力するスクリプト書きました

テンプレート

Markdown形式のテンプレートを作成します
記述しやすくするため、YAMLのキー名を日本語にしてたんですが、テンプレートでもそのまま参照できました

screen.hbs
# {{画面名}}
{{説明}}

## 画面イメージ
![]({{画像path}})

## 画面項目

  {{#each 画面項目}}

---

### {{名称}} ({{id}})

| ラベル     | 種類     | 入出力区分     | 表示/非表示     | 入力可/入力不可     | 型     | 桁数                                                                                | 表示フォーマット                       | 入力チェック    |
| ------- | ------ | --------- | ---------- | ------------ | ----- | --------------------------------------------------------------------------------- | ------------------------------ | ---------- |
| {{ラベル}} | {{種類}} | {{入出力区分}} | {{表示/非表示}} | {{入力可/入力不可}} | {{}} | {{#with 桁数}}{{#if min}} 最小:{{min}}{{/if}}{{#if max}}最大:{{max}}{{/if}}{{/with}} |  {{表示フォーマット}}  | {{入力チェック}} |

 {{#if 初期表示}}
 #### 初期表示

{{初期表示}}
 {{/if}}


 {{#if 説明}}
 #### 説明

{{説明}}
 {{/if}}

{{#if 備考}}
 #### 備考

{{備考}}
 {{/if}}

{{/each}}

感想

よかった点

  • 設計書書く時に、バリデーションチェックかかるのめっちゃいい
    • Schemaファイルを修正すると、すべての設計書で都度検証かかることで、記述が揃う
  • YAMLは複数行の文字列を入れやすい&見やすいので、設計書の主な記述である、表形式・自由記述のいずれの形式にも対応できる
    • ここにMarkdown入れられるので、記述効率も上がる(アウトラインは使えないけど、箇条書き・表形式など)
screen.yml
イベント:
  - id: init 
    名称: 初期処理
    項目id: 
    操作区分: その他
    画面遷移: 
    処理ID:
    入力:
    出力: 
    説明: | 
      - マスタデータ(Master)を用いて、紐づく入力項目の選択肢を生成する
      - 初期値を設定する
        - 画面入力情報が無い場合は、空白 or 初期表示の値を設定する
        - 画面入力情報が既にある場合は、該当する項目に保存されている値を表示する

いまいちな点

  • 一通り記述した後、ちょっとだけ修正したい時に、変換するのが面倒くさい・忘れがち
    • 何かでファイルの修正を感知してコマンド実行する的なものを仕込めば解決しそうだけど、今回至りませんでした…

今後やってみたいこと

  • 決まったキーワードと遷移先を定義しておいて、自動でリンク作成する的なこと
    • 設計書の相互参照って便利だしWikiの特性だと思うので使えるようにしてみたい
  • pdf に出力

参考

YAML書き方

https://qiita.com/tfrcm/items/5f8e4c5795ce41b214d1#%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%E9%85%8D%E5%88%97
https://magazine.rubyist.net/articles/0009/0009-YAML.html

JSON Schema書き方

https://www.ikemo3.com/manual/json-schema/
https://qiita.com/arumi8go/items/a9530cbd39ff545a7bbb

handlebars書き方

https://qiita.com/sassy_watson/items/f9947624876bf75a9eff

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[JavaScript] JSDocにしっかりかく

参考

JavaScriptでJSDocコメントを書くメリットとは
JSDoc使い方メモ すごく詳しい

JSDoc

JSDocコメントとは関数や変数の宣言の直前に/** ◯◯ */を書く記法のことです。(引用:JavaScriptでJSDocコメントを書くメリットとは)

なぜ導入しようと思ったか?

同じような名前の関数が多かったので、何がなんだが分からなくなった。
(命名の問題もあるが...)

こんな感じ

/**
 * [description]
 * @param {*} answerSet 
 */

https://devdocs.io/jsdoc/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでバイナリを扱いたい

JavaScriptでバイナリのデータを扱う方法をまとめてみました。

1. データの表現

バイナリのデータを扱うために、ArrayBuffer、TypedArray、DataViewというオブジェクトが利用できます。Node.jsであれば、Bufferというオブジェクトもあります。以下、順に説明していきます。

1) ArrayBuffer

最も基本的なデータ構造で、メモリ上の連続した領域を表しています。
書き込みなどの操作はできないので、直接ArrayBufferを触る機会は少ないと思います。

  // 256バイトのArrayBufferを作る
  let buffer = new ArrayBuffer(256);

  // ArrayBufferを変更することはできない 
  buffer[0] = 1; // xxx 意味なし

2) TypedArray

ES6で新しく導入されたオブジェクトで、文字通り、型付けされた値の配列を示します。種類としては、以下のようなものがあります。

  • Int8Array
  • Uint8Array
  • Uint8ClampedArray
  • Int16Array
  • Uint16Array
  • Int32Array
  • Uint32Array
  • Float32Array
  • Float64Array

TypedArrayを生成するには、次のようなコードを書きます。

  // 要素数が3つのUint32Arrayを生成する
  let array = new Uint32Array(3);

  // 中身を埋める
  array[0] = 0xA1A2A3A4;
  array[1] = 0xB1B2B3B4;
  array[2] = 0xC1C2C3C4;

このとき、バイトオーダーはどうなっているのでしょうか? 実は、面倒なことに、環境依存となっています。
バイトオーダーがBig Endianになる環境であれば、arrayの中身は、次のようになります。

     Big Endian の場合:
     +-------------------+-------------------+-------------------+
     | A1 | A2 | A3 | A4 | B1 | B2 | B3 | B4 | C1 | C2 | C3 | C4 |
     +-------------------+-------------------+-------------------+

一方、バイトオーダーがLittle Endianになる環境であれば、arrayの中身は、次のようになります。

     Little Endian の場合: 
     +-------------------+-------------------+-------------------+
     | A4 | A3 | A2 | A1 | B4 | B3 | B2 | B1 | C4 | C3 | C2 | C1 |
     +-------------------+-------------------+-------------------+

なお、現在の環境がどちらであるか、簡単に確認する方法を、最後の付録のところに載せておきます。

TypedArrayでは、filterやmapなど、一般的な配列のメソッドが利用できます。

  // 100を超える要素だけを残す
  let over100 = array.filter((e) => {
      return (e > 100);
  });

3) DataView

ArrayBufferに対して、任意の位置での読み書きをできるようにするものです。

  // ArrayBufferを作る
  let buffer = new ArrayBuffer(256);

  // ArrayBufferを変更するため、DataViewを作る
  let dv = new DataView(buffer);

DataViewでは、バイナリを、Int8、Uint16など、任意の型の配列とみなすことができます。例えば、Int8とみなして、先頭に値をセットするならば、次のように書けます。

  let buffer = new ArrayBuffer(256);
  let dv = new DataView(buffer);
  dv.setInt8(0, 3); // 0番目(先頭)に3という値をセットする

Int8の代わりにUint32としたければ、次のように書けます。

  dv.setUint32(1, 0xA1A2A3A4); // 1番目にA1A2A3A4という値をセットする

なお、ここでいう「1番目」というのは、1バイト目、という意味ではありません。
Uint32は、32ビットの値であり、4バイトの幅を取りますので、次のように4バイト目からセットされることになります。

       0    1    2    3    4    5    6    7    8    9    10   11
     +-------------------+-------------------+-------------------+
     |    |    |    |    | A1 | A2 | A3 | A4 |    |    |    |    |
     +-------------------+-------------------+-------------------+
       ↑                   ↑                   ↑
    0番目                1番目                2番目

この図でも分かる通り、DataViewの操作におけるバイトオーダーは、Big Endianです。何かの事情でLittle Endianにしたい場合には、オプションで指定することができます。

  /*
   * 3番目の引数でバイトオーダーを指定できる
   */
  dv.setUint32(1, 0xA1A2A3A4); // Big Endian
  dv.setUint32(1, 0xA1A2A3A4, true); // Little Endian
  dv.setUint32(1, 0xA1A2A3A4, false); // Big Endian

4) Buffer (Node.js)

Node.jsでは、Unit8Arrayに相当する役割を持つデータ構造として、Bufferがあります。
比較的、操作用のメソッドが潤沢に揃っていて、便利に使えます。

  // 256バイトのBufferを作る
  let buffer = Buffer.alloc(256);

  // 先頭のバイトに1をセットする
  buffer[0] = 1;

2. BASE64

ネットワークでバイナリデータを送信するときには、BASE64に変換することが多いと思いますので、BASE64についても、説明しておきます。

1) BASE64とは?

バイナリを以下の64種類の文字だけで表す表現方法です。

  • アルファベット(a-z, A-z)
  • 数字(0-9)
  • 記号(+/)

なお、実際にはパディングのために「=」を使いますので、65文字になります。

2) バイナリからBASE64へ

Node.jsの場合は、BufferオブジェクトのtoString()を使うことができます。

  // BufferをBASE64に変換する
  let base64 = buffer.toString('base64');

ブラウザの場合は、btoa()で変換できるのですが、この関数は引数として文字列を取るので、バイナリデータを変換するには、少し工夫がいります。

  // ArrayBufferをBASE64に変換する
  let base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

このワンライナーの処理を説明すると、以下のような処理になっています。

  • もとのArrayBufferを、TypedArray(Uint8Array)に変換する
  • スプレッド演算子(...)で配列の中身を取り出す
    • 例: [89, 43, 90, 61] -> 89, 43, 90, 61
  • String.fromCharCodeで、それぞれの数字をASCIIコードとみなして、文字に変換
  • btoaで、BASE64にエンコード

なお、スプレッド演算子が使えない環境では、次のように書くことができます。

  let base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));

3) BASE64からバイナリへ

Node.jsの場合は、Bufferが使って、次のようにします。

  // BASE64をBufferに変換する
  let base64 = buffer.toString('base64');

ブラウザの場合は、次のようにします。

  /*
   * BASE64をUint8Arrayに変換する
   */
  let binary = atob(base64);
  let len = binary.length;
  let bytes = new Uint8Array(len);
  for (let i = 0; i < len; i++)        {
    bytes[i] = binary.charCodeAt(i);
  }
}

付録

実行環境のエンディアンをチェックするのは簡単で、以下のような関数を使うことができます。trueが返ればBig Endian、falseが返ればLittle Endianです。

function isBigEndian() {
  let uInt32 = new Uint32Array([0x11223344]);
  let uInt8 = new Uint8Array(uInt32.buffer);
  return (uInt8[0] === 0x11);
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者によるjavaScriptによるpreventDefaultについての学習

今回はpreventDefaultです。

preventDefaultとは「要素に設定された規定の動作をキャンセルする」です。

例として長い本文を途中で区切り、「続きを読む」などをクリックさせて全文を表示されるというものです。

  <style>
    .hidden {display:none;}
  </style>

  <p>
    text. text. text. text. text.   <span class="hidden">
    text. text. text. text. text. text. text. text. text. 
    text. text. text. text. text. </span><a href="">続きを読む</a>
  </p>

適当にこうしておきます。

次に

main.js
  const a = document.querySelector('a');
  const span = document.querySelector('span');

  a.addEventListener('click', () => {
    a.classList.add('hidden');
    span.classList.remove('hidden');
  });

このように書いておきます。
aとspanを定義して、aをクリックしたらhiddenクラスをつけて[続きを読む]を非表示にし、
逆にspanからhiddenクラスを外すことで全文表示させるというもの。

ただしこれだと、クリックした一瞬表示されるがすぐ戻ってしまいます。
それはなぜかというと<a href="">と空のため、このページ自体に遷移し元の状態に戻ったから。

それを解消するための手段の一つとして、preventDefaultを使う。
繰り返しになるが、preventDefaultとは「要素に設定された規定の動作をキャンセルする」。
aタグの規定の動作「ページ遷移」をキャンセルさせることで、元の状態に戻るのを防ぐ目的です。

main.js
  a.addEventListener('click', e => { // ()をeに変更
    e.preventDefault();
    a.classList.add('hidden');
    span.classList.remove('hidden');
  });

では次は、本文省略時は「続きを読む」、全文表示時には「省略する」にして、表示非表示を切り替えられるようにしましょう。

  <p>
    text. text. text. text. text.   <span class="hidden">
    text. text. text. text. text. text. text. text. text. 
    text. text. text. text. text. </span><a href=""></a>
  </p>

html側ではaタグの中身を削除。

main.js
  const a = document.querySelector('a');
  const span = document.querySelector('span');

    a.textContent = '続きを読む'

  a.addEventListener('click', e => {
    e.preventDefault();
    if (span.classList.contains('hidden')) {
      span.classList.remove('hidden');
      a.textContent = '省略する'
    } else {
      span.classList.add('hidden');
      a.textContent = '続きを読む'
    }
  });

JavaScript側では、まずaのテキストに続きを読むを追加し
spanのhiddenクラスがあるかないかで切り分けてみました。

とりあえずはこれで切り替えられるようです。
(本当はtoggleを使いたかったのですが、どうもうまく行かなったです。
もしアドバイスいただければ嬉しいです)

preventDefaultは何かと使えそうです。
何かをやらせたいのに、別の動作が引っかかるときなどに重宝しそうですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Three.jsを使ってみる①

Three.jsとは?

three.jsは3次元コンピュータグラフィックスを描画するJavascriptのライブラリである. three.jsのページでは様々なサンプルが公開されており, 幅広い3DCGのプログラミングが可能なことがわかる.更にWebブラウザで動作するので手軽に始めることができる.

three.jsのダウンロード

ここのdownloadからthree.jsを取ってくる.

基本的な使い方

three.jsを記述する場所を決める

ここを参考にコーディングをしていく.

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <title>My first three.js app</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script src="js/three.js"></script>
        <script>
            // ここにコードを書いていく
        </script>
    </body>
</html>

シーンの作成

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

//3DCGの描画範囲と場所を指定する
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

このコードでははじめにシーンを作成し, カメラを設置する.最後にレンダラーを作成する.今回はbodyに直接シーンを描画する.

オブジェクトを置く

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

ここでは, 箱型のジオメトリ(図形)を作成し, その箱の材質をを決めてシーンに追加している.最後にカメラ位置をz軸方向に5進めている.

アニメーションと描画

function animate() {
    requestAnimationFrame( animate );
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render( scene, camera );
}
animate();

ここでは先程設置した箱を回転させるアニメーションの作成と, シーンの描画をしている.

実行結果

Screenshot from 2019-08-27 01-10-38.png

箱が回転している.

おわりに

今回はthree.jsのチュートリアルに沿って進めていった.ここに使い方など詳しく書いてあるので, それを参考にしながら実際に触ることをおすすめする.続きの記事も書いていく予定.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Notifications APIを上書きしてまとめて通知する

Notificationクラスを上書きしてキューにためておく。通知を制御するExtensionなんかが作れないかなーと思ってメモ

let queue = []

class MyNotification {
    constructor(title, options) {
        queue.push({title: title, options: options})
    }

    static async notify(notifications) {
        for (let i in notifications) {
            new OrgNotification(notifications[i].title, notifications[i].options)
            await new Promise(r => setTimeout(r, 1000))
        }
    }
}

OrgNotification = Notification
Notification = MyNotification

new Notification("title1")
new Notification("title2")
new Notification("title3")

await Notification.notify(queue)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む