20200320のHTMLに関する記事は16件です。

Electronでカレンダーを作る③

前回からの続き

前回はカレンダーの中身が動的に表示されるようにした。

表示する月を変えられるようにする

先月、来月に切り替えられるようにしたい。

先月と来月切り替えボタンを配置する。

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ElectronCalendar</title>
  <script text="text/javascript" src="./js/index.js"></script>
  <link rel="stylesheet" href="./css/index.css">
</head>
<body>
  <div class="calendar-wrapper">
    <div class="preMonthButton">
      <button type="button" id="preMonth"><先月</button>
    </div>
    <div class="nextMonthButton">
      <button type="button" id="nextMonth">来月></button>
    </div>
    <table id="table" class="calendar">
      <caption id="caption"></caption>
      <thead>
        <tr>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr id="row1">
          <td id="cell1"></td>
          <td id="cell2"></td>
          <td id="cell3"></td>
          <td id="cell4"></td>
          <td id="cell5"></td>
          <td id="cell6"></td>
          <td id="cell7"></td>
        </tr>
        <tr id="row2">
          <td id="cell8"></td>
          <td id="cell9"></td>
          ・・・略
          <td id="cell33"></td>
          <td id="cell34"></td>
          <td id="cell35"></td>
        </tr>
        <tr id="row6"> ※
          <td id="cell36"></td>
          <td id="cell37"></td>
          <td id="cell38"></td>
          <td id="cell39"></td>
          <td id="cell40"></td>
          <td id="cell41"></td>
          <td id="cell42"></td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>

※カレンダーに6行目を追加している。

index.js
'use strict';

const moment = require("moment");

window.onload = function() {
    createCallendar(moment());

    //先月ボタン押下時
    document.getElementById('preMonth').onclick = function() {
        createCallendar(moment(this.value));
    }

    //来月ボタン押下時
    document.getElementById('nextMonth').onclick = function() {
        createCallendar(moment(this.value));
    }
}

/**
 * カレンダーを表示する。
 * @param momentオブジェクト 
 */
const createCallendar = function(localMoment) {
    //captionを表示
    document.getElementById('caption').innerText = localMoment.format("YYYY年MM月");

    //カレンダー初期化
    clearCallendar();

    //当月の日数を取得
    const daysOfMonth = localMoment.daysInMonth();

    //月初の曜日を取得(index.htmlと合わせるために+1する)
    const firstDayOfManth = localMoment.startOf('month').day() + 1;

    //カレンダーの各セルに日付を表示させる
    let cellIndex = 0;
    for(let i = 1; i < daysOfMonth + 1; i++) {
        if(i === 1) {
            cellIndex += firstDayOfManth;
        } else {
            cellIndex++;
        }
        document.getElementById("cell" + cellIndex).innerText = i;
    }

    //6行目の第1セルが空白なら6行目自体を非表示にする。
    if(document.getElementById("cell36").innerText === "") {
        document.getElementById('row6').style.visibility = "hidden";
    }

    //先月
    document.getElementById('preMonth').value = localMoment.add(-1,'month').format("YYYY-MM");
    //来月(先月のmomentオブジェクトとなっているので+2ヶ月)
    document.getElementById('nextMonth').value = localMoment.add(2,'month').format("YYYY-MM");
}

/**
 * カレンダーを初期化する
 */
const clearCallendar = function() {
    //6行目を表示させておく
    if(document.getElementById('row6').style.visibility === "hidden") {
        document.getElementById('row6').style.visibility = "visible";
    }
    for(let i = 1; i < 43; i++) {
        document.getElementById("cell" + i).innerText = "";
    }
}

6行目は表示しない場合がある(表示しない場合の方が多い)ので、表示しない場合は隠す。

$ electron .

初期表示
image.png

6行目がある場合
image.png

とりあえず出来たけどボタンがダサい。

TODO

・月を切り替えた場合、同一html内の表示内容の切り替えとなっているため、いちいち初期化が必要で微妙。新しく画面を読み込むようにしたい。
・ボタンの見た目をナウい感じにしたい。

あとがき

Electronの記事じゃ無く、HTMLとJSの記事みたいになってる・・・。

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

レスポンシブにしたのに、なぜかなっていない。そんな時の確認。

せっかくレスポンシブに対応しているようにコードを書いたのに、サーバーにあげるとレスポンシブになっていない。

結論 head要素を見ましょう

ヘッド要素の中(railsならapplication.html)の中身に

<meta name="viewport" content="width=device-width, initial-scale=1.0">

hamlなら

%meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}/

こちらを記入しましょう。

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

【ラジオボタンより簡単!】jQueryで表示・非表示を実装する方法

CSSでうまく行くと思っていたのに...

最初はラジオボタンにdisplay:noneで
コーディングを行っていのですがタブがズレるズレる...
下に行ったかと思えば次は上に行くし、ため息ばかり...

CSSでは歯が立たず『jQuery』で実装を行うことに。

jQueryの方が簡単でした!

mypage.js
$(function(){
  $('.mypage--list--info').click(function () {
    $('.tab--list--info').show();
    $('.info-go-list').show();
    $('.tab--list--todo').hide();
    $('.todo-go-list').hide();
  });

  $('.mypage--list--todo').click(function () {
    $('.tab--list--todo').show();
    $('.todo-go-list').show();
    $('.tab--list--info').hide();
    $('.info-go-list').hide();
  });

  $('.goods-purchase--transaction').click(function () {
    $('.tab-list--transaction').show();
    $('.transaction-go-list').show();
    $('.tab-list--post').hide();
    $('.post-go-list').hide();
  });

  $('.goods-purchase--post').click(function () {
    $('.tab-list--post').show();
    $('.post-go-list').show();
    $('.tab-list--transaction').hide();
    $('.transaction-go-list').hide();
  });
})

うまく表示されました!

481c5c10c2dce6e766a2335c50fddb7c.png

jQueryでのコーティングは単調な繰り返しが多く、簡単に記載することができました。
CSSの方で実装頑張ってた自分がバカだった...1週間無駄にした...

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

HTMLのtableをソートする方法

概要

  • Tableをソートするライブラリを書きました

    • 外部ライブラリなどは不要
    • シンプルなので素のHTMLやBootstrapなど特にフレームワーク縛りなく使える
    • ソートのみが欲しかったので容量小さめ
  • ソースコードはこちらで公開しています

デモ

See the Pen sortable-table (with Bootstrap4) by Tom Misawa (@riversun) on CodePen.

使い方

TableのHTML

  • sortable-tableクラスをもった要素以下にtable theadを置く
  • th要素にdata-id属性でデータとひもづけるidを指定する
  • ソートしたい列にはsortable属性をつける

以下のようになる。

ソートできるテーブルのHTML
<div class="sortable-table">
    <table id="my-table1">
        <thead>
        <tr>
            <th data-id="id" data-header>
                <div>#</div>
            </th>
            <th data-id="name" sortable>
                name
            </th>
            <th data-id="price" sortable>
                price($)
            </th>
            <th data-id="weight" sortable>
                weight(carat)
            </th>
        </tr>
        </thead>
    </table>
</div>

テーブルにデータを入れる

  • 以下のようにテーブルに表示させたいデータを行ごとに配列で指定する
  • 要素名とさきほどHTMLで定義したdata-id属性が紐付く
 const data = [
    {
      id: 0,
      name: 'Diamond',
      weight: 1.0,
      price: 9000,
    },
    {
      id: 1,
      name: 'Amethyst',
      weight: 3.0,
      price: 200,
    },
    {
      id: 2,
      name: 'Emerald',
      weight: 2.5,
      price: 2500,
    },
    {
      id: 3,
      name: 'Ruby',
      weight: 2.0,
      price: 2000,
    },
  ];

  const sortableTable = new SortableTable();
  // table要素を指定する
  sortableTable.setTable(document.querySelector('#my-table1'));
  // テーブルに表示したいデータを指定する
  sortableTable.setData(data);
  • setTableでソートできるようにしたいtable要素を指定する
  • setDataでテーブルに表示したいデータを指定する

See the Pen sortable-table (with plain HTML) by Tom Misawa (@riversun) on CodePen.

ソートした結果を受け取り処理する

ソート結果はgetDataで取得できる。
setDataで元のデータを指定するが、ソートしても元のデータは変更しないようにしているので、ソート済のデータを取得したい場合はgetDataか後述のイベントコールバックから取得する。

const sortedData=sortableTable.getData();

ソートイベントを受け取る

テーブルのヘッダ部分がクリックされ、ソートが実行されるとソートイベントが発火する
以下のようにイベントリスナーを登録するとソートされたときイベントがコールバックされる。

  sortableTable.events()
    .on('sort', (event) => {
      console.log(`[SortableTable#onSort]
      event.colId=${event.colId}
      event.sortDir=${event.sortDir}
      event.data=\n${JSON.stringify(event.data)}`);
    });
  • event.colIdには列のid(=data-id)が格納される
  • event.sortDirにはソート方向(=asc or desc)
  • event.dataにはソート済のデータが格納される

ソートをコードから実行する

ユーザーのクリックではなく、コードからソートを(強制的に)実行する方法は以下の通り

ソートをコードから実行する
sortableTable.sort('price', 'asc');

sortableTable.sort([id], [sortDir]);のように指定する。

sortDirにソート方向を指定する
- asc・・・昇順ソート。昇順とは 1,2,3,4 のようになる
- desc・・・降順ソート。降順とは4,3,2,1 のようになる
- toggle・・・現在のソート方向を反転する。

ソートを初期状態に戻す

最初にデータを指定したときの状態に戻すときはresetData

初期状態に戻す
sortableTable.resetData();

ソートをコードから実行するデモ

https://riversun.github.io/sortable-table/index_with_bootstrap.html

まとめ

  • 拙作のソートライブラリについてお読みいただきありがとうございました
  • 何かのお役にたてますと幸いです

ソースコードについて

npm install @riversun/sortable-table
  • CDNからも利用可能です
<script src="https://cdn.jsdelivr.net/npm/@riversun/sortable-table@1.0.0/lib/sortable-table.js"></script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者用】htmalでwebサイトを作るときにまず入れる必須タグ

htmlでサイトをつくる際にまず知るべき事


htmalでwebサイトを作るときに基本的には

     「head」 「body」 「footer」

の3つの部分によって構成されています。


このあたりに関してはprogaetを学んでいる方ならご存知かとは思います。しかし、いざ実際にページを作成してみるとheadには何を入れればいいのか?、


bodyはどんな風にみせればいいの?という疑問が生まれるのではないでしょうか。そこで今日は
head前に入れるものとhead内冒頭にまず最初に必ず入れるべきコードをお伝えします。


そもそもheadとは

headはユーザーが見ることはできないwebサイトの基盤となっている部分です。



レストランで言えば厨房のようなイメージです。
このhead=厨房内で文字コードを入力し料理するからこそユーザーに見えやすいコンテンツが提供されているとそんな風に捉えて頂ければ大丈夫です。



!DOCTYPE html

htmlにてwebページを作成する際にこの文章はhtmlで書きます!と宣言する必要があリます。

そこでこの!DOCTYPE htmlをいれることによってこのファイルhtmalで作成します!と宣言することができるんですね。

この!DOCTYPE htmlまずファイルを作成した一番はじめに入れるようにしましょう



html lang=“ja”

次にすべき事はこのhtmlコードは日本語で描きます!と宣言する作業です。

html lang=“ja”とありますが英語の場合はhtml lang=“en”となり、それぞれの言語に合わせて最初に入れておきましょう。



meta charset="utf-8"

コンピューター上には文字を理解するために必要な文字コードというものが存在します。

このmeta charset="utf-8"は文字コードの指定を表していますのmetaって何?という方、

metaタグについてはまたお伝えしますが、いまはこのmeta charset="utf-8"を入力するとパソコン側がutf-8をつかえばいいのね!と理解してくれると覚えてください。





プログラミングはただ丸暗記する必要はありませんが基盤となる概念は理解して置く必要があります。なぜこのコード、タグが必要なのか、そこだけ理解できれば他を暗記する必要はありません。


次回はその他にheadに入れるべきタグをご紹介します。

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

Electronでカレンダーを作る②

前回からの続き

前回は画面まで作成した。
カレンダーの内容を動的に表示する処理を作成していく。

カレンダーの中身を作っていく

日付操作を楽にするためmomentモジュールを使う。

$ npm install -D moment

index.htmlを修正していく。

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ElectronCalendar</title>
  <script text="text/javascript" src="index.js"></script>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div class="calendar-wrapper">
    <table class="calendar">
      <caption id="caption"></caption>
      <thead>
        <tr>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td id="cell1"></td>
          <td id="cell2"></td>
          <td id="cell3"></td>
          <td id="cell4"></td>
          <td id="cell5"></td>
          <td id="cell6"></td>
          <td id="cell7"></td>
        </tr>
        ・・・略
          <td id="cell27"></td>
          <td id="cell28"></td>
        </tr>
        <tr>
          <td id="cell29"></td>
          <td id="cell30"></td>
          <td id="cell31"></td>
          <td id="cell32"></td>
          <td id="cell33"></td>
          <td id="cell34"></td>
          <td id="cell35"></td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>

7(曜日) × 5(週)の箱を作って各セルにIDを振っておく。

index.js
'use strict';

const moment = require("moment");

window.onload = function() {
    //captionを表示
    document.getElementById('caption').innerText = moment().format("YYYY年MM月");

    //当月の日数を取得
    const daysOfMonth = moment().daysInMonth();

    //月初の曜日を取得(index.htmlと合わせるために+1する)
    const firstDayOfManth = moment().startOf('month').day() + 1;

    //カレンダーの各セルに日付を表示させる
    let cellIndex = 0;
    for(let i = 1; i < daysOfMonth + 1; i++) {
        if(i === 1) {
            cellIndex += firstDayOfManth;
        } else {
            cellIndex++;
        }
        document.getElementById("cell" + cellIndex).innerText = i;
    }
}

月初の曜日が分かればそれ以降の日付の曜日も一意に決まる。
カレンダーの特性上、1番上の行のセルには値が必ず一個は入るので、cellIndex += firstDayOfManth; で初日のセルの位置を設定して、後は日数分インクリメントしていく。

月初はmomentモジュールのmoment().startOf('month')で楽に取得できる。

$ electron .

image.png

祝日を赤字にするにはどっかでデータを持っておかないと無理そう。

TODO

年月を変更できるようにする。

あとがき

momentモジュールが便利。

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

Railsのtext_fieldにCSSをあてる方法

text_fieldにCSSってどうやってあてるんだっけ?

Railsアプリケーション作成時にフロント部分を作成していた時に

example.haml.html
.item__name
  商品名
  .name--input
    = f.text_field :name, placeholder: "40文字まで"

のようなhamlを作成していざscssを記述しようとしたときに
このtext_filedにどうやってCSSをあてるのかが
ふと考えると分からなかったんです。

同じようなnumber_fieldsubmitなどにも使えるやり方なので
是非覚えておいたほうがよいです。

そもそもtext_fieldで作られるHTMLは何なのか?

上の= f.text_field :name, placeholder: "40文字まで"で作られるHTMLを
chromeの検証で確認してみると
<input placeholder="40文字まで" type="text" name="item[name]" id=item_name>
というものが作成されているのがわかるかと思います。

text_fieldとかはRailsがviewを簡潔に記述するために用意してくれているヘルパーメソッドのため
簡単な記述で実際はこういうHTML文の作成もしてくれています。
この作成されたHTMLにあてるようにCSSを記述すればOKです。

今回はSCSSを使い記述しました。

CSSをあててみよう

example.scss
.item__name{
  input[type="text"]{
    width: 100%;
    height: 20px;
    font-size: 14px;
  }
  ::placeholder{
    padding: 5px 5px;
  }
}

と指定して記述すると、text_fieldにCSSをあてることができます。
placholderはCSSの擬似要素のため上記のような記述をする必要があります。

ヘルバーメソッドを使って記述した場合にどのようなHTML文が作成されているのかを確認すると解決できる部分でしたね。

参考先

rails フォームの大きさをcssで変更する

CSS: カスケーディングスタイルシート::placeholder

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

Electronでカレンダーを作る①

はじめに

皆さん、Electron触っていますでしょうか?
私は最近Electronの存在を知ったので、JavaScriptの勉強も兼ねてカレンダーアプリを作成してみようと思った次第です。

とりあえずElectronプロジェクトを作る。

$ mkdir ElectronCalender
$ cd ElectronCalender/
$ npm init -y
$ npm install -D electron ※

これでディレクトリ内にElectronを使う準備は整った。
※npm install -D ~ はpackage.jsonに書き込みらしい。

画面を作ってアプリを立ち上げる。

package.jsonにエントリーポイント(main.js)を指定しとく。

package.json
{
  "name": "ElectronCalender",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^8.1.1"
  }
}

main.jsの中身

main.js
'use strict';

// Electronのモジュール
const electron = require("electron");

// アプリケーションをコントロールするモジュール
const app = electron.app;

// ウィンドウを作成するモジュール
const BrowserWindow = electron.BrowserWindow;

// メインウィンドウはGCされないようにグローバル宣言
let mainWindow;

// 全てのウィンドウが閉じたら終了
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// Electronの初期化完了後に実行
app.on('ready', function() {
  // メイン画面の表示。ウィンドウの幅、高さを指定できる
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたらアプリも終了
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

mainWindow.loadURL('file://' + __dirname + '/index.html'); で表示する画面(htmlファイル)を読み込む。

html,cssはこんな感じ(ほぼ参考書の内容を丸写しした)

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ElectronCalender</title>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div class="calendar-wrapper">
    <table class="calendar">
      <caption>2020年3月</caption>
      <thead>
        <tr>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td>4</td>
          <td>5</td>
          <td>6</td>
          <td>7</td>
        </tr>
        <tr>
          <td>8</td>
          <td>9</td>
          <td>10</td>
          <td>11</td>
          ・・・略
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>
index.css
.calendar-wrapper {
    width: 750px;
}

.calendar {
    table-layout: fixed;
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #ccddcc;
    vertical-align: middle;
}

.calendar th,
.calendar td {
    padding: 10px 0;
    border: 1px solid #cdcdcd;
    text-align: center;
    vertical-align: top;
    font-size: 35px;
}

.calendar th {
    background-color: #dedede;
}

/* 日曜日1行目(見出し) */
.calendar th:first-child {
    background-color: #e05557;
    color: #ffffff;
}

/* 日曜日 */
.calendar td:first-child {
    color: #e05557;
}

/* 土曜日1行目(見出し) */
.calendar th:last-child {
    background-color: #207bcf;
    color: #ffffff;
}

/* 土曜日 */
.calendar td:last-child {
    color: #207bcf;
}

/* 祝日 */
.holiday {
    color: #e05557;
}

.calendar caption {
    margin: 0 0 10px 0;
    padding: 10px;
    font-size: 23px;
    border: 5px solid #dedede;
    border-radius: 30px;
    font-weight: bold;
}

アプリを起動する。

ディレクトリ直下で
$ electron .

image.png

良い感じな気がする。

TODO

日付、祝日をhtml内にベタ書きしているのでjsを使って動的にカレンダーの内容が作成されるようにしたい。

あとがき

作っていて気がついたけどカレンダーのスペルは「calender」じゃなくて「calendar」だった。

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

Railsでページ毎にsubmitの表記を変えたい

submitボタンの表記を変えたい

submitボタンを実装した場合、デフォルトの日本語表記は下記のような形で表示されます
(色付けなどはCSSで加工済み)

スクリーンショット 2020-03-20 14.09.19.png

'登録する' というのがデフォルトのsubmitボタンとなります。

例えば、作成しているアプリで商品出品するページでは当然、'出品する'という表記にしたいですよね。
しかし、商品を編集して更新する場合は、'出品する'だと違和感があるので
'更新する'と表記をしたいところです。

しかし、出品も更新も同じフォームを流用しているので
分岐分けで記入する必要があるところになります。

単純にsunmitボタンのテキストを変えたい場合なら
<input type="submit" value="出品する">
を使えば表記は変わるわけなのですが、上記のように分岐わけさせたいときにどうするべきか。
出品と更新のページを別々に作って、各々でテキスト表記を変えるという手段もできますが
メンテナンス上、ほぼ同じ記述のコードのファイルが増えてしまうのは避けたいところです。

ja.ymlを利用して分岐させる

ja.ymlといえば、英語表記を日本語化させる指定を記述する場所なのですが
こちらでアクション毎にsubmitの表記を指定させることができます。

まずはi18nの導入が必要なので参考先にあるページを参照に導入を済ませておいてください
[初学者]Railsのi18nによる日本語化対応

config/locales/ja.ymlに記述する

ja.yml
ja:
  helpers:
    submit:
      create: "出品する"
      update: "更新する"

このように記述をするとcreate下のsubmitは出品すると表示され
update下のsubmitは更新すると表示されるようになります。

実際にcreate時はこのように変更がかかります。
スクリーンショット 2020-03-20 14.09.41.png
update画面も同様に記述した通りの変更がかかります。

これでhtmlをcreateとupdateで別々に表記を分ける必要がなくなるので
ファイルを増やすことなく分岐して表示させることができます。

参考先

[初学者]Railsのi18nによる日本語化対応

http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-submit

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

WebにおけるUIのキーボード操作まとめ

Webアプリケーションを実装する上でHTMLのキーボード操作について調べたメモです。

なぜ、キーボード操作が必要なのか

  • 運動障害を持つ多くのユーザーはキーボードに依存している(これは健常者が怪我した場合も含まれる)
  • 視覚障害のあるユーザーも通常、ナビゲーションにキーボードを使用する
  • 一部のユーザーはキーボードを模倣した別のハードウェアを使う場合がある
  • もしかしたら、マウスが壊れてキーボードしか使えない状況もありうる
  • というか、普通にキーボードで操作できると便利じゃないですか?

WCAG 2.1の「ガイドライン2.1 操作可能」では以下のように記載されています。

すべての機能をキーボードから利用できるようにすること。

HTMLキーボード操作一覧

キーボード操作はアクセシビリティにおいて重要な部分です。キーボードを通してページを操作できるだけでなく、予測可能であることが重要です。これには一般的なキーボード操作の理解が必要になります。

次の表にはオンラインにおけるインタラクションの標準キーストロークおよび考慮すべき情報が記載されています。

インタラクション キーストローク Tab Enter SpaceBar 方向キー Esc 備考
要素移動 ・Tabによる前方移動
・Shift + Tabによる後方移動
・フォーカスインジケータが表示されている必要がある
・移動の順序は論理的かつ直感的でなければいけない
リンク Enter
ボタン EnterもしくはSpaceBar role="button" の要素で両方のキーコマンドが有効であること
チェックボックス SpaceBarによってチェックボックスのON/OFFを切り替える 複数のオプションを選択できる場合はチェックボックスを使用すること
ラジオボタン ・方向キー(↑→↓←)でオプションを選択
・Tabで次のオプションに移動
1つのオプションを選択できる場合はラジオボタンを使用すること
ドロップダウンメニュー ・方向キー(↑↓)でオプション移動
・SpaceBarでメニューを展開
オートコンプリート ・入力時にフィルタリングを開始
・方向キー(↑↓)でオプションを移動
・Enterでオプションを選択
ダイアログ Escで閉じる ・モーダルダイアログはキーボードフォーカスを維持する必要がある
・モードレスダイアログはフォーカスを失うと閉じる
・ダイアログを閉じた場合、フォーカスは通常ダイアログを開いた要素に戻る
スライダー ・方向キー(↑→↓←)で値の増減 ・ダブルスライダー(範囲選択)の場合はTab、Shift + Tabで両端を切り替える
・一部のスライダーではPageUp/PageDownにより増減できる
・Home/Endで開始/終了に移動する場合もある
メニューバー ・方向キー(↑↓)でオプションを移動
・方向キー(←→)でサブメニューの開閉
・Enterでオプションを展開もしくは選択
・すべてのメニューにこれらのコントロールがあるわけではない。よりシンプルなメニューはTab/Enterに依存する
タブパネル ・Tabでタブグループの中に入り、Tabでタブグループの外に移動する
・方向キー(↑→↓←)で前後のタブに移動
・これは新しくロードせずにタブ移動できるタブ用
・タブが別のページへのリンクの場合はTab + Enterが適切
・方向キーを押すと、タブのコンテンツが自動で更新される(Enterキーは基本的に使わない)
ツリーメニュー ・方向キー(↑↓)でオプションを移動
・方向キー(←→)でサブメニューの開閉もしくは1階層移動
スクロール ・方向キー(↑↓)で垂直にスクロール
・方向キー(←→)で水平スクロール
・SpaceBar / Shift + SpaceBarでページ単位でスクロール
水平スクロールは最小限にする
フォーム ・基本的にEnterでサブミット(備考参照) ・サブミットボタンがある場合はinput要素に限らず、Enterでサブミットできる
・Enterキーでサブミットしたくない場合はサブミットボタンをdisabledにする
・サブミットボタンが無い場合はinput要素の数が1つか複数かで挙動が異なる
・1つの場合はEnterキーでサブミットできる
・複数の場合はEnterキーでサブミットできない

※予測可能といいつつ、フォームの挙動は条件分岐が多くて分かりにくい気がする...

注意事項

  • 上記の操作はすべてのブラウザでの動作を保証するものではありません。(Chrome v80.0.3987.132では動作しました)
  • 上記のキーボード操作はあくまで標準のHTMLコンポーネントを使用した場合に機能します。 もし、コンポーネントを独自に実装している場合は上記の機能が無効化されている可能性があることに注意してください。

もし、補足や間違いなどありましたら、ぜひ教えてください。

参考記事

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

WebのUIにおけるキーボード操作まとめ

Webサイト/アプリケーションを実装する上で独自のフォーム部品を実装する場合、キーボード操作のサポートは意外と忘れられがちではないでしょうか?(これまで僕自身もあまり対応できていませんでした...)
今回は標準のHTMLコンポーネントがどのようにキーボード操作できるのかを把握し、自身でキーボード操作を実装する場合に参考となる情報をまとめました。

なぜ、キーボード操作をサポートするのか

  • 運動障害を持つ多くのユーザーはキーボードに依存している(これは健常者が怪我した場合も含まれる)
  • 視覚障害のあるユーザーも通常、ナビゲーションにキーボードを使用する
  • 一部のユーザーはキーボードを模倣した別のハードウェアを使う場合がある
  • もしかしたら、マウスが壊れてキーボードしか使えない状況もありうる
  • というか、普通にキーボードで操作できると便利じゃないですか?

WCAG 2.1の「ガイドライン2.1 操作可能」では以下のように記載されています。

すべての機能をキーボードから利用できるようにすること。

HTMLキーボード操作一覧

キーボード操作はアクセシビリティにおいて重要な部分です。キーボードを通してページを操作できるだけでなく、予測可能であることが重要です。これには一般的なキーボード操作の理解が必要になります。

次の表にはオンラインにおけるインタラクションの標準キーストロークおよび考慮すべき情報が記載されています。

インタラクション キーストローク Tab Enter SpaceBar 方向キー Esc 備考
要素移動 ・Tabによる前方移動
・Shift + Tabによる後方移動
・フォーカスインジケータが表示されている必要がある
・移動の順序は論理的かつ直感的でなければいけない
リンク Enter
ボタン EnterもしくはSpaceBar role="button" の要素で両方のキーコマンドが有効であること
チェックボックス SpaceBarによってチェックボックスのON/OFFを切り替える 複数のオプションを選択できる場合はチェックボックスを使用すること
ラジオボタン ・方向キー(↑→↓←)でオプションを選択
・Tabで次のオプションに移動
1つのオプションを選択できる場合はラジオボタンを使用すること
ドロップダウンメニュー ・方向キー(↑↓)でオプション移動
・SpaceBarでメニューを展開
オートコンプリート ・入力時にフィルタリングを開始
・方向キー(↑↓)でオプションを移動
・Enterでオプションを選択
ダイアログ Escで閉じる ・モーダルダイアログはキーボードフォーカスを維持する必要がある
・モードレスダイアログはフォーカスを失うと閉じる
・ダイアログを閉じた場合、フォーカスは通常ダイアログを開いた要素に戻る
スライダー ・方向キー(↑→↓←)で値の増減 ・ダブルスライダー(範囲選択)の場合はTab、Shift + Tabで両端を切り替える
・一部のスライダーではPageUp/PageDownにより増減できる
・Home/Endで開始/終了に移動する場合もある
メニューバー ・方向キー(↑↓)でオプションを移動
・方向キー(←→)でサブメニューの開閉
・Enterでオプションを展開もしくは選択
・すべてのメニューにこれらのコントロールがあるわけではない。よりシンプルなメニューはTab/Enterに依存する
タブパネル ・Tabでタブグループの中に入り、Tabでタブグループの外に移動する
・方向キー(↑→↓←)で前後のタブに移動
・これは新しくロードせずにタブ移動できるタブ用
・タブが別のページへのリンクの場合はTab + Enterが適切
・方向キーを押すと、タブのコンテンツが自動で更新される(Enterキーは基本的に使わない)
ツリーメニュー ・方向キー(↑↓)でオプションを移動
・方向キー(←→)でサブメニューの開閉もしくは1階層移動
スクロール ・方向キー(↑↓)で垂直にスクロール
・方向キー(←→)で水平スクロール
・SpaceBar / Shift + SpaceBarでページ単位でスクロール
水平スクロールは最小限にする
フォーム ・基本的にEnterでサブミット(備考参照) ・サブミットボタンがある場合はinput要素に限らず、Enterでサブミットできる
・Enterキーでサブミットしたくない場合はサブミットボタンをdisabledにする
・サブミットボタンが無い場合はinput要素の数が1つか複数かで挙動が異なる
・1つの場合はEnterキーでサブミットできる
・複数の場合はEnterキーでサブミットできない

フォームのEnterキーによるサブミットの挙動を確認するためのWebページをこちらに用意しています。予測可能が重要といいつつ、フォームの挙動は条件分岐が多くて分かりにくい気がする...

注意事項

  • 上記の操作はすべてのブラウザでの動作を保証するものではありません。(Chrome v80.0.3987.132では動作しました)
  • 上記のキーボード操作はあくまで標準のHTMLコンポーネントを使用した場合に機能します。 もし、コンポーネントを独自に実装している場合は上記の機能が無効化されている可能性があることに注意してください。

もし、補足や間違いなどありましたら、ぜひ教えてください。

参考記事

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

初心者によるプログラミング学習ログ 267日目

100日チャレンジの267日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
267日目は、

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

A-Frameでカメラをトラッキング

A-Frame

バーチャルリアリティ体験を構築するためのオープンソースのWebフレームワークの一つです。
https://aframe.io

Entity Component System

スクリーンショット 2020-03-20 0.58.45.png

A-FrameのEntity Component SystemのComponentは外観・動作・機能を構築するためにEntity上で組み合わせ・照合・および構成できるJavascriptモジュールです。
JavaScriptでComponentを登録し、DOMから宣言的に使用できます。
Componentは構成可能・再利用可能・および共有可能です。

A-FrameアプリケーションのほとんどのコードはComponent内に存在する必要があります。

A-Frameから

カメラをトラッキングするコンポーネントの作成

常にカメラの正面に移動させ、カメラの方向を向かせる機能のコンポーネント(camera-tracking)を作成し、文字とボックスのエンティティに組み込みます。

スクリーンショット 2020-03-20 1.25.38.png

スクリーンショット 2020-03-20 1.25.54.png

コード

HTML

index.html
<html>
 <head>
  <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
  <script src="tracking.js"></script>
 </head>

 <body>
  <a-scene>
   <!--Camera-->
   <a-entity id="camera" camera></a-entity>
   <!--Field-->
   <a-sky color="#44AAFF"></a-sky>
   <a-plane position="0 0 -5" rotation="-90 0 0" width="6" height="6" color="#BB9944" shadow></a-plane>
   <!--Camera-tracking Text-->
   <a-entity id="text" camera-tracking="circleR: 2; shiftX: 1; shiftY: 0.1"
             text="font: mozillavr; value: Tracking test.; color: black" 
             scale="3 3 1">
   </a-entity>
   <!--Camera-tracking Box-->
   <a-entity id="box" camera-tracking="circleR: 3; shiftX: 0; shiftY: -0.5"
             geometry="primitive: box"
             scale="0.8 0.3 0.2" material="color: red" shadow>
        </a-entity>
  </a-scene>
 </body>
</html>

JavaScript

tracking.js
AFRAME.registerComponent('camera-tracking', {

  schema: {
    circleR: {type: 'float', default: '1'},
    shiftX: {type: 'float', default: '0'},
    shiftY: {type: 'float', default: '0'}
  },

  tick: function () {
    var camera = document.querySelector('#camera');

    var cameraPosition = camera.object3D.position;
    var cameraRotation = camera.object3D.rotation;

    // center position
    var cameraX = cameraPosition.x;
    var cameraY = cameraPosition.y;
    var cameraZ = cameraPosition.z;

    // rotation degree
    var degreePit = (cameraRotation.x * 180 / Math.PI);
    var degreeYaw = (cameraRotation.y * 180 / Math.PI);

    // circle size
    var r = this.data.circleR;

    // rotation point
    var positionY = Math.sin(degreePit / 180 * Math.PI) * r;
    var xzr = Math.cos(degreePit / 180 * Math.PI) * r;
    var positionX = Math.cos((degreeYaw + 90) / 180 * Math.PI) * xzr;
    var positionZ = Math.sin((degreeYaw + 90) / 180 * Math.PI) * -1 * xzr;

    // shift x value
    var addX = this.data.shiftX;
    var addXPosX = Math.sin((degreeYaw + 90) / 180 * Math.PI) * addX;
    var addXPosZ = Math.cos((degreeYaw + 90) / 180 * Math.PI) * addX;

    // shift y value
    var addY = this.data.shiftY;
    var addYPosX = Math.sin(degreePit / 180 * Math.PI) * Math.cos((degreeYaw + 90) / 180 * Math.PI) * -1 * addY;
    var addYPosY = Math.sin((degreePit + 90) / 180 * Math.PI) * addY;
    var addYPosZ = Math.sin(degreePit / 180 * Math.PI) * Math.sin((degreeYaw + 90) / 180 * Math.PI) * addY;

    // set properties
    this.el.setAttribute('rotation', degreePit +' '+ degreeYaw +'  0');
    this.el.setAttribute('position', (positionX + cameraX + addXPosX + addYPosX)+' '+ (positionY + cameraY + addYPosY) +' '+ (positionZ + cameraZ + addXPosZ + addYPosZ));

  }
});

解説

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

A-FrameでWebVRのカメラをトラッキング

A-Frame

バーチャルリアリティ体験を構築するためのオープンソースのWebフレームワークの一つです。
https://aframe.io

Entity Component System

スクリーンショット 2020-03-20 0.58.45.png

A-FrameのEntity Component SystemのComponentは外観・動作・機能を構築するためにEntity上で組み合わせ・照合・および構成できるJavascriptモジュールです。
JavaScriptでComponentを登録し、DOMから宣言的に使用できます。
Componentは構成可能・再利用可能・および共有可能です。

A-FrameアプリケーションのほとんどのコードはComponent内に存在する必要があります。

A-Frameから

ECS(エンティティ・コンポーネント・システム)とは、主にゲーム開発で使用されているソフトウェアアーキテクチャパターンです。ECSは継承よりコンポジションの原則に従うことで、より柔軟にエンティティを定義することを可能にしています。

カメラをトラッキングするコンポーネントの作成

常にカメラの正面に移動させ、カメラの方向を向かせる機能のコンポーネント(camera-tracking)を作成し、文字とボックスのエンティティに組み込みます。
また、camera-trackingのプロパティとしてカメラからの「半径・X距離・Y距離」を与えることで画面レイアウトをしやすくします。

スクリーンショット 2020-03-20 1.25.38.png

スクリーンショット 2020-03-20 1.25.54.png

コード

HTML

index.html
<html>
 <head>
  <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
  <script src="tracking.js"></script>
 </head>

 <body>
  <a-scene>
   <!--Camera-->
   <a-entity id="camera" camera></a-entity>
   <!--Field-->
   <a-sky color="#44AAFF"></a-sky>
   <a-plane position="0 0 -5" rotation="-90 0 0" width="6" height="6" color="#BB9944" shadow></a-plane>
   <!--Camera-tracking Text-->
   <a-entity id="text" camera-tracking="circleR: 2; shiftX: 1; shiftY: 0.1"
             text="font: mozillavr; value: Tracking test.; color: black" 
             scale="3 3 1">
   </a-entity>
   <!--Camera-tracking Box-->
   <a-entity id="box" camera-tracking="circleR: 3; shiftX: 0; shiftY: -0.5"
             geometry="primitive: box"
             scale="0.8 0.3 0.2" material="color: red" shadow>
        </a-entity>
  </a-scene>
 </body>
</html>

JavaScript

tracking.js
AFRAME.registerComponent('camera-tracking', {

  schema: {
    circleR: {type: 'float', default: '1'},
    shiftX: {type: 'float', default: '0'},
    shiftY: {type: 'float', default: '0'}
  },

  tick: function () {
    var camera = document.querySelector('#camera');

    var cameraPosition = camera.object3D.position;
    var cameraRotation = camera.object3D.rotation;

    // center position
    var cameraX = cameraPosition.x;
    var cameraY = cameraPosition.y;
    var cameraZ = cameraPosition.z;

    // rotation degree
    var degreePit = (cameraRotation.x * 180 / Math.PI);
    var degreeYaw = (cameraRotation.y * 180 / Math.PI);

    // circle size
    var r = this.data.circleR;

    // rotation point
    var positionY = Math.sin(degreePit / 180 * Math.PI) * r;
    var xzr = Math.cos(degreePit / 180 * Math.PI) * r;
    var positionX = Math.cos((degreeYaw + 90) / 180 * Math.PI) * xzr;
    var positionZ = Math.sin((degreeYaw + 90) / 180 * Math.PI) * -1 * xzr;

    // shift x value
    var addX = this.data.shiftX;
    var addXPosX = Math.sin((degreeYaw + 90) / 180 * Math.PI) * addX;
    var addXPosZ = Math.cos((degreeYaw + 90) / 180 * Math.PI) * addX;

    // shift y value
    var addY = this.data.shiftY;
    var addYPosX = Math.sin(degreePit / 180 * Math.PI) * Math.cos((degreeYaw + 90) / 180 * Math.PI) * -1 * addY;
    var addYPosY = Math.sin((degreePit + 90) / 180 * Math.PI) * addY;
    var addYPosZ = Math.sin(degreePit / 180 * Math.PI) * Math.sin((degreeYaw + 90) / 180 * Math.PI) * addY;

    // set properties
    this.el.setAttribute('rotation', degreePit +' '+ degreeYaw +'  0');
    this.el.setAttribute('position', (positionX + cameraX + addXPosX + addYPosX)+' '+ (positionY + cameraY + addYPosY) +' '+ (positionZ + cameraZ + addXPosZ + addYPosZ));

  }
});

解説

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

JavaScriptで *タブ* を作成する方法 windowオブジェクト

タブとは何か?

タブとはドキュメントを切り替えて表示するためのGUIウィジェットである。一般的には長方形のボックス中にテキストラベルを表示する形で画面上部に表示され、タブの選択により管理するドキュメントを切り替えて表示させる仕組みとなっている。

wikipedia
https://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%96_(GUI)

<完成品>
タブが作成されます!
スクリーンショット 2020-03-20 0.40.12.png
スクリーンショット 2020-03-20 0.39.53.png
スクリーンショット 2020-03-20 0.40.04.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<a href="javascript:window.open('sample2.html','','')">開く</a>

</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="top">
        新しいウィンドウ
        <!-- !ウィンドウを閉じる -->
        <a href="javascript:window.close()">閉じる</a>
    </div>

</body>
</html>

なんとHTMLにワンライナーでの記述で完了です。
<a>タグに javascript:window.open('sample2.html','','')記述します。



window.open
windowオブジェクトとはJavaScriptにあらかじめ用意されてるオブジェクトで、JavaScriptを何も書いてない状態でもwindowオブジェクトは利用する事が出来る。

windowオブジェクトについて
https://developer.mozilla.org/ja/docs/Web/API/Window

('sample2.html','','')
1つめがファイル名、2つめがウィンドウ名、3つめがプロパティが入ります。

簡単に記述できますね!
しかし、プライバシポリシー等で使用するケースは多いですよね!
是非開発の使ってみては?

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

永遠に続くクソ計算クイズ2 typescriptで

成果物

https://yuzuru2.github.io/neta1/dist/

リポジトリ

https://github.com/yuzuru2/yuzuru2.github.io/tree/master/neta1

UI

無題.png

src/index.ts

// くそIEに対応させる
import 'babel-polyfill';

class Calculation {
  private static instance: Calculation;

  // 秒数
  private count = 15;

  // タイマーで使う
  private time_id;

  // シングルトン
  private constructor() {}

  // dom
  private readonly id_left = document.getElementById('left');
  private readonly id_sign = document.getElementById('sign');
  private readonly id_right = document.getElementById('right');
  private readonly id_ans = document.getElementById('ans');
  private readonly id_time = document.getElementById('time');
  private readonly id_yes = document.getElementById('yes');
  private readonly id_no = document.getElementById('no');

  // 問題セット
  private set_question(left, sign, right) {
    this.id_left.textContent = left;
    this.id_sign.textContent = sign;
    this.id_right.textContent = right;
  }

  // 答えセット
  private set_answer(ans: string) {
    this.id_ans.textContent = ans;
  }

  // 足し算
  private sum(ans: boolean) {
    const _left = Math.floor(Math.random() * 100) + 1;
    const _right = Math.floor(Math.random() * 100) + 1;

    this.set_question(_left, '+', _right);

    if (ans) {
      this.set_answer(`${_left + _right}`);
      return;
    }

    // 不正解作成パターン1
    if (Math.floor(Math.random() * 2) === 0) {
      this.set_answer(
        `${_left + _right + (Math.floor(Math.random() * 3) + 1)}`
      );
    } else {
      // 不正解作成パターン2
      this.set_answer(
        `${_left + _right - (Math.floor(Math.random() * 3) + 1)}`
      );
    }
  }

  // 引き算
  private minus(ans: boolean) {
    const _left = Math.floor(Math.random() * 100) + 1;
    const _right = Math.floor(Math.random() * 100) + 1;

    this.set_question(_left, '-', _right);

    if (ans) {
      this.set_answer(`${_left - _right}`);
      return;
    }

    // 不正解作成パターン1
    if (Math.floor(Math.random() * 2) === 0) {
      this.set_answer(
        `${_left - _right + (Math.floor(Math.random() * 3) + 1)}`
      );
    } else {
      // 不正解作成パターン2
      this.set_answer(
        `${_left - _right - (Math.floor(Math.random() * 3) + 1)}`
      );
    }
  }

  // 掛け算
  private multiplication(ans: boolean) {
    const _left = Math.floor(Math.random() * 10) + 1;
    const _right = Math.floor(Math.random() * 10) + 1;

    this.set_question(_left, '×', _right);

    if (ans) {
      this.set_answer(`${_left * _right}`);
      return;
    }

    // 不正解作成パターン1
    if (Math.floor(Math.random() * 2) === 0) {
      this.set_answer(
        `${_left * _right + (Math.floor(Math.random() * 3) + 1)}`
      );
    } else {
      // 不正解作成パターン2
      this.set_answer(
        `${_left * _right - (Math.floor(Math.random() * 3) + 1)}`
      );
    }
  }

  // 割り算
  private division(ans: boolean) {
    let _left;
    let _right;

    while (1) {
      _left = Math.floor(Math.random() * 100) + 1;
      _right = Math.floor(Math.random() * 10) + 1;
      if (_left % _right === 0) {
        break;
      }
    }

    this.set_question(_left, '÷', _right);

    if (ans) {
      this.set_answer(`${_left / _right}`);
      return;
    }

    // 不正解作成パターン1
    if (Math.floor(Math.random() * 2) === 0) {
      this.set_answer(
        `${_left / _right + (Math.floor(Math.random() * 3) + 1)}`
      );
    } else {
      // 不正解作成パターン2
      this.set_answer(
        `${_left / _right - (Math.floor(Math.random() * 3) + 1)}`
      );
    }
  }

  // リセット
  private reset() {
    // タイマー処理
    const time_method = () => {
      this.id_time.textContent = `${--this.count}`;

      if (this.count === 0) {
        alert('タイムアップ');
        this.reset();
        return;
      }
      this.time_id = setTimeout(time_method, 1000);
    };

    clearTimeout(this.time_id);

    this.count = 15;
    this.time_id = setTimeout(time_method, 1000);

    // 時間セット
    this.id_time.textContent = `${this.count}`;

    // 正解・不正解どちらの問題を出すか決める
    const ans = Math.floor(Math.random() * 2) === 0;

    // 計算種類
    const _sign = Math.floor(Math.random() * 4);
    switch (_sign) {
      case 0:
        this.sum(ans);
        break;

      case 1:
        this.minus(ans);
        break;

      case 2:
        this.multiplication(ans);
        break;

      case 3:
        this.division(ans);
        break;

      default:
        break;
    }

    // yesボタンを押したとき
    this.id_yes.onclick = () => {
      ans ? alert('正解') : alert('不正解');
      this.reset();
    };

    // noボタンを押したとき
    this.id_no.onclick = () => {
      ans ? alert('不正解') : alert('正解');
      this.reset();
    };
  }

  // シングルトン 単一のインスタンスを返す
  public static get_instance(): Calculation {
    if (!this.instance) {
      this.instance = new Calculation();
    }

    // 生成済みのインスタンスを返す
    return this.instance;
  }

  // クイズをスタートする
  public start() {
    this.reset();
  }
}

Calculation.get_instance().start();

見返してみると、とんでもねーくそコードだな

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