- 投稿日:2019-03-23T23:51:35+09:00
 
jQueryオブジェクトは$だけではないことを知っていますか?
こんにちは。俳句や川柳から動くGIF画像を生成できるWebサービス「五七五メーカー」をリリースしたアカネヤ(@ToshioAkaneya)です。
jQueryオブジェクトとは、ここでは有名な
$のこととします。
$('.class-name')の様に使いますよね。jQueryオブジェクトは$だけではないことを知っていますか?
大したことではないのですが、jQueryを導入すると、
jQueryというオブジェクトもグローバルで定義されます。$ === jQueryはTrueです。
$は、ChromeのJS Consoleで定義済みの関数のため、そのサイトにjQueryが入っているか確かめるのにはjQueryが定義されているか確かめるのがおすすめです。はてなブックマーク・Pocketはこちらから
- 投稿日:2019-03-23T23:27:37+09:00
 
JavaScriptの基礎をやってみての感想
自己紹介
初めまして。aikig(アイキグ)(@aikig0926)と申します。
某情報系大学に在籍中の大学生です。昨年9月から大学でプログラミングが始まり、そこからハマって春休み(1月下旬頃)から独学でプログラミングを勉強してます!
今の目標はインターンに参加してスキルアップがしたいです。よろしくお願いします。スキルと経緯
大学でHTML/CSSの基礎の基礎やProcessingをやってました。HTML/CSSはさておき、Processingがグラフィック系が強く数学重視(座標概念が苦手)ということで挫折。
HTML/CSSをやりつつ何か無いかなと模索していた時にPHPカンファレンスに行ったことが転機でした。そこで初めてウェブ系言語を知り、そのあとHTML/CSSを経てJavaScriptをやり始めました。
春休みの最初(2月終わり)まではHTML/CSSをやってました。
JavaScriptを始めたのは3月からでJavaScriptって何それ???から始めてます。
Processingのときはあまりモチベ無かったんですが、JavaScriptやり始めてめっちゃ楽しい〜ってなってます。やったこと
初心者独学マンの定番?ドットインストール。Progateもやってます。
最初ドットインストールだけでいいかなっていうノリで始めて、マジわけわからん(>_<)ってなったのでProgateから始めることを勧めます。ここで一つ問題があってJavaScriptって最近バーションアップがあってProgateもドットインストールもレッスンの全てが最新版になってません。
Progateは特に学習コースのみで道場コースはないです。でも学習コースをやれば基礎はわかると思います。・Progate JavaScriptES6 ⅴ以外
基礎の基礎なので理解できるまでやることを勧めます。(オブジェクト概念とか初めてやる方は特に自分は3周くらいしました)多くても3周くらいまでだと思います。ドットインストールなどでコードを書くうちに自然と理解します。
※ⅴはいらないかなーって感じでやってないです。はい。
個人差あると思いますがスライドがマジ神・ドットインストール
1 初めてのJavaScript
2 詳細JavaScript 基礎文法編
3 詳細JavaScript オブジェクト編
4 詳細JavaScript DOM編やるレッスンはこの辺り。あとは個々のやりたい、作りたいものに応じてレッスンを進めていけばいいと思います。
自分はオブジェクト編が終わったあとDOM編をやらずにおみくじに入ったので反省してます。。。DOMを全く知らずにコードを書きまくるのはコスパ悪いです(笑)期間としては大体20日くらい。レッスンが多いこととオブジェクト概念に苦しんだ結果だと思ってます。長かったです。。。
自分は初心者の定番?じゃんけんゲームを作りました。
最初はドットインストールのおみくじを作るレッスンをやって、そこからじゃんけんに。
できたー
— aikig(アイキグ) (@aikig0926) 2019年3月20日
最後にバカなミスで時間食ったけどw 定義文でイコール二ついれてたのに気づかないとかバカすぎ自分。これからアレンジ
達成感がすごい pic.twitter.com/NPqXF3fKIf
こんな感じ。今はこのじゃんけんゲームをもっとレベルアップさせてます。
感想
確かにHTML/CSSよりはハードルが2段くらい上がる。
でも、実際にコードを書いて動くのは嬉しいし、いろんなことができるのはいい。
JavaScriptやるうちに自分がいかにグラフィックに向いてないかが分かりました(笑)多分ですが、初心者の最初の壁がコマンド(命令)長くね?っていう問題とオブジェクト概念だと思います。
個人的な解決策ですが、コードを書きまくればどうにかなります。自分もゲームとかをドットインストールで作るうちになんとなくはわかったかな?って感じになりました。
完璧求めるとキリがないので5割程度でもOKという気持ちで。
重要なのは、コードを知ることと使い方を何となく知ることだと思います。
あとはひたすら実践! 簡単なものから自分のポートフォリオにしていくこと!!1ヶ月くらいで基礎の基礎はできると思うので初心者の方もProgate→ドットインストールの順でやってみるといいと思います。
一回で理解できないと思いますが、(自分もそうだったし、今も途中)コードを書きまくるうちに理解できるので基礎の基礎を乗り切って自分のやりたい、作りたいプロダクトを作っていきましょう!
自分も苦しい時もありましたが、プログラミングが好き、〇〇を作りたい!って気持ちがあったらここまでこれたと思います。尊敬する某先生も言ってましたが初心者こそ情熱です!!最後に
お読みいただきありがとうございました。初心者の方のお役に立てれば幸いです。
参考
- 投稿日:2019-03-23T23:11:50+09:00
 
TypeScriptでnpmライブラリ開発ことはじめ
この記事では、わざわざTypeScriptでnpmライブラリ開発したいという読者を対象としています。
とはいえ今どきはVS Codeさんという素晴らしいエディターのおかげもあって、型が提供されていないnpmライブラリは使いづらい立場にあります。
では早速ですが、TypeScriptで"Hello だれだれ"とコンソールに表示されるnpmライブラリを開発してみましょう。
基本的なnpmライブラリ開発の知識
この記事では「TypeScriptで」npmライブラリ開発することに主眼を置きたいため、基本的なnpmライブラリ開発の知識は「本当にやさしいnpmライブラリ開発入門」くらいは知っている前提で進めます。
package.jsonのあれこれ私の趣味は人の書いた
package.jsonを見ることです。(趣味悪いでしょうw)ではまずは今回お題にする
package.jsonを見ていただきましょう。package.json{ "name": "hello-world-typescript", "version": "1.0.0", "main": "dist/index.js", "license": "MIT", "files": [ "dist" ], "scripts": { "build": "tsc", "prepublishOnly": "npm run build" }, "devDependencies": { "typescript": "^3.3.4000" } }とても綺麗ですよね。
ひとつひとつ意味があるので解説していきます。
package.json#namenpmライブラリの名前です。
require('xxx')のxxxにあたるアレです。
package.json#versionnpmライブラリはこのバージョン情報を毎回インクリメントして公開する必要があります。
TypeScriptが一度
3.3.3333というアレなバージョンをつけてしまったために、3.3.4にできずに3.3.4000になってしまったのは、笑えない笑える話として有名かもしれませんね。
package.json#mainここに相対パスで有効なJavaScriptファイルが指定されていないと
require('xxx')できません。
今回はTypeScriptのビルド結果を読み込ませたいので、dist/index.jsになっています。
package.json#files
package.jsonのfilesプロパティは、使う人と使わない人がいると思います。
Webpackのincludeオプションとexcludeオプションに似ていて、前者はpackage.jsonのfilesプロパティ、後者は.npmignoreです。要はnpmはライブラリを
npm publishコマンドで公開する際に、filesプロパティが指定してあればそれらのみを公開対象とします。TypeScriptは
tscコマンドでビルドする前提なので、filesプロパティにビルド結果フォルダを指定してやると楽だよ、という話になるわけです。
package.json#scripts
npm run xxxを作れるプロパティですね。
npm run buildは実際にはtscコマンドを実行するところはみなさんお分かりかと思います。
prepublishOnlyがニッチなやつで、npm publishをする「前に」必ず実行されるという意味になります。
今回はnpm run buildを必ず走らせてからライブラリ公開したいので、これを指定しています。(開発したのにビルド忘れてバージョンしか上がらなかったという事故を防ぐやつです。)ちなみに、
scriptsプロパティにはいくつかのマジックがありまして、それが今回のpreにあたります。例えば
npm run xxxを実行する場合、prexxxとpostxxxを作成しておくと、それぞれ実行前と後に指定されたコマンドが叩かれたりします。
(なかなか便利なのですが駆使しすぎるとpackage.jsonの管理が大変になるので注意。)
tsconfig.jsonお待たせしました。
みなさんこれが早く見たかったですよね。ご査収ください。
tsconfig.json{ "compilerOptions": { "target": "esnext", "module": "commonjs", "moduleResolution": "node", "strict": true, "skipLibCheck": true, "declaration": true, "pretty": true, "newLine": "lf", "outDir": "dist" } }ニッチなところだけ説明していきますね。
targetとmoduleはどのようなライブラリの種類にするのか(Node.jsで利用されるのか、ブラウザで利用されるのか等)によって変わってきます。今回は最新のNode.jsで叩くだけのライブラリですのでtarget: "esnext"のmodule: "commonjs"になります。Node.jsで利用される場合は常にmodule: "commonjs"と覚えておいても構いません。せっかくなのでTypeScriptにきちんと仕事をさせたい。なので
strict: trueにします。
でもライブラリのエラーが無限に出てくることがあるので、それは無視するためにskipLibCheck: trueにします。型定義をきちんと出力したいので、
declaration: trueにします。あとWindowsで開発したい方は、クロスプラットフォームでの利用を念頭に改行コードをLFに寄せます。そのために
newLine: "lf"します。
(例えばコマンドラインツール系のnpmライブラリをWindowsで開発した際に、Linux等で実行するとエラーになります。それを防ぐために改行コードをLFに寄せます。)最後に今回は
distフォルダにコンパイル結果を出力したいので、outDir: "dist"とします。TypeScriptでnpmライブラリ開発
やっと開発に入りますが、もう終わったようなものです。
src/index.tsfunction hi(name: string) { console.log(`Hello ${name}`); } export default hi;ビルドしてみます。
$ npm run build
distにビルド結果が出ました。dist/index.js"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function hi(name) { console.log(`Hello ${name}`); } exports.default = hi;型定義も出力されています。
dist/index.d.tsdeclare function hi(name: string): void; export default hi;最後にnpmライブラリとして公開してみます。
$ npm publishちゃんと
npm run build(tsc)されてから公開されましたね。まとめ
- TypeScriptはコンパイル作業が必要なので、事前準備がひと手間かかる
 - それをクリアすればTypeScriptでもサクサクnpmライブラリ開発ができる!
 いかがでしたでしょうか。
私は.NETやらTypeScriptやらでMicrosoftさんにはお世話になっていますが、型安全なのはとても気持ちいいです。少しでも皆さまのお役に立てたらと思います。
では良いTypeScriptライフを!!
- 投稿日:2019-03-23T21:18:40+09:00
 
Qiitaユーザのつながりを可視化するWebページを作成してみた
はじめに
Qiitaでは、ユーザをフォローすることで、ユーザ間でつながりをもつことができます。今回は、指定したユーザの、フォローしているユーザとフォローされているユーザを、ネットワーク図で可視化するWebページを作成してみました。
作成物
ソースコード(HTMLとJavaScript)を、githubで公開しています。
https://github.com/t-mangoe/QiitaUserNetwork
作成したWebページには、以下からアクセスできます。
https://t-mangoe.github.io/QiitaUserNetwork/
Webページでは、以下の図のようにネットワーク図が表示されます。
処理内容
QiitaのWebAPIを叩いて、フォローしているユーザとフォローされているユーザの情報を取得します。この情報を基にvis.jsでネットワーク図を作成し、表示しています。
- 投稿日:2019-03-23T20:35:31+09:00
 
Node.jsのrequireの引数に変数を利用して動的に読み込む
環境
Node.js v10.13.0
本題
requireを使って他のモジュールやファイルを動的に読み込みたい場合、
変数をrequireの引数に利用することになる。しかし、以下のようにすると上手くいかない。
上手くいかない.jslet path = 'path/foo'; require('./' + path);
require(...)とした場合には引数は静的である必要があるらしい。なので、以下のようにコールバックを利用して動的な読み込みをおこなう。
正しく動く.jslet path = './path/foo'; require([path], function (foo) // path/fooモジュールが変数fooにロードされている );コールバックなので若干使い勝手は悪いけれど、
条件によって読み込むモジュールを変更できるのは便利。参考文献
参考文献というか、公式サイトに上の内容がちゃんと書かれていた...
- 投稿日:2019-03-23T20:24:57+09:00
 
アップロード前に画像を非同期でプレビューする 解説・備忘録(jQuery)
どんな内容?
こんにちは!
Rails開発六ヶ月の卵エンジニアです!ちょっと前にアイコン画像を非同期でプレビューさせるときにこちらを参考にして実装したので、
今回はその備忘録を兼ねて、理屈を解説しつつ、ここに保存しておこうと思います。(結局MDNのFileReaderを読み込めば実装できるので、正確な学習をするならこっち見た方がいいかも)
私と同じような駆け出しの仲間へ、何かしらの助けになれば幸いです。
ソースコード
コードは参照したサイトのものをほぼそのまま。
JSFiddleにも記述しておきましたので、
よろしければ挙動確認はこちらをお使いください。preview.jsfunction readURL(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function(e) { $('#imgPre').attr('src', e.target.result); } reader.readAsDataURL(input.files[0]); } } $("#imgInp").change(function() { readURL(this); });preview.html<!-- jQueryの読み込み すでに導入してあれば不要 --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <form> <input type='file' id="imgInp" /> <img id="imgPre" src="#" alt="your image" /> </form>処理の流れ
要するに
1 inputタグで選択した画像のパスを、
2 プレビューしたいimgタグのsrcに代入し、
3 ブラウザ側からsrcを元に画像を読み込ませる。という流れになります。
記述の解説
① inputタグを用意・イベント発火
ファイルアップロードのため、inputタグを用意します。
preview.html<input type='file' id="imgInp" />今回は画像を選択した際にプレビューを表示させたいので、
inputタグの中身が変更されたタイミングで処理が発火されるようにします。preview.js$("#imgInp").change(function() { readURL(this); });➁ ③ プレビューしたいimgタグ用意・プレビューさせる
プレビューしたい場所にimgタグを置いておきます
preview.html<img id="imgPre" src="#" alt="your image" />①のpreview.jsで発火するreadURL関数の中身、
プレビュー処理を記述します。preview.jsfunction readURL(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function(e) { $('#imgPre').attr('src', e.target.result); } reader.readAsDataURL(input.files[0]); } }FileReaderオブジェクトについてはこちらを。
FileReaderはFileオブジェクトを使用してユーザーのコンピュータから非同期でファイルを読み込みます。
Fileオブジェクトはinput要素でファイルを選択した際に得られるFileListオブジェクト(input.files)内に。
今回はその先頭の(input.file[0])を指定して、プレビュー対象のFileオブジェクトを選択しています。readAsDataURLメソッドを使い、ユーザーが入力したFileオブジェクト(input.file[0])を読み込みます。
preview.jsreader.readAsDataURL(input.files[0])reader.onloadプロパティに処理を記述します。
そうすることでreadAsDataURLメソッドが完了すると発火するloadイベント時にここが実行されます。プレビューしたいimgタグのsrcにURLを代入
preview.jsreader.onload = function(e) { $('#imgPre').attr('src', e.target.result); }これで完了です。
まとめ
いかがでしたでしょうか。
FileReaderオブシェクトの使い方さえわかっていれば特に難しく考えずに実装できるのかなと思います。
基本的にコピペすればそのまま動くと思いますが、
機能を拡張したくなった時や、応用する時に理屈を知ってないと難しいですね。技術解説は初めてなので、至らぬ点や、間違った表現・解説をしていた場合は、ぜひお知らせください。
- 投稿日:2019-03-23T20:01:04+09:00
 
DataTablesで合計値を表示する
はじめに
業務系のシステムでは表組みで情報を表示することがよくありますが、そんな時に便利なのがDataTablesです。
ページングやソートといった、よくあるけど自前で用意すると地味に手間な機能が用意されているのでとても助かります。
https://datatables.netそんなDataTablesを利用して集計を行った場合に、合計値をDataTablesの外で表示するための備忘録です。(合計値以外でも可能ですね)
Footer callback
まずはDataTables内で表示するパターンです。
公式サイトの実装例通り、footerCallback関数を利用します。
https://datatables.net/examples/advanced_init/footer_callback.htmlsample.html$(document).ready(function() { $('#example').DataTable( { "footerCallback": function ( row, data, start, end, display ) { var api = this.api(), data; // Remove the formatting to get integer data for summation var intVal = function ( i ) { return typeof i === 'string' ? i.replace(/[\$,]/g, '')*1 : typeof i === 'number' ? i : 0; }; // Money delimiter var moneyVal = function (i) { var valAry valAry = String(i).split('.') valAry[0] = valAry[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') return valAry.join('.') }; // Total over all pages total = api .column( 4 ) .data() .reduce( function (a, b) { return intVal(a) + intVal(b); }, 0 ); // Total over this page pageTotal = api .column( 4, { page: 'current'} ) .data() .reduce( function (a, b) { return intVal(a) + intVal(b); }, 0 ); // Update footer $( api.column( 4 ).footer() ).html( '$'+ moneyVal(pageTotal) +' ( $'+ moneyVal(total) +' total)' ); } } ); } );Draw callback
次に本題のDataTables外で表示するパターンですが…こちらも公式サイトのReferenceに載っています。
drawCallback関数を利用し、DOM操作で結果を反映します。
https://datatables.net/reference/option/drawCallback例えば
<p id="total"></p>という合計値の表示領域があったとすると、下記のようになります。sample.html$(document).ready(function() { $('#example').DataTable( { "drawCallback": function( settings ) { var api = this.api(); // Remove the formatting to get integer data for summation var intVal = function ( i ) { return typeof i === 'string' ? i.replace(/[\$,]/g, '')*1 : typeof i === 'number' ? i : 0; }; // Money delimiter var moneyVal = function (i) { var valAry valAry = String(i).split('.') valAry[0] = valAry[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') return valAry.join('.') }; // Total over all pages total = api .column( 4 ) .data() .reduce( function (a, b) { return intVal(a) + intVal(b); }, 0 ); // Total over this page pageTotal = api .column( 4, { page: 'current'} ) .data() .reduce( function (a, b) { return intVal(a) + intVal(b); }, 0 ); // Update value window.$('#total').html('$'+moneyVal(pageTotal) +' ( $'+ moneyVal(total) +' total)'); } } ); } );footerCallback関数とほとんど同じですね。
おわりに
DataTables、便利です。
- 投稿日:2019-03-23T19:55:33+09:00
 
公式ドキュメントリンク集(JS,API)
延々と足して行く。増えたら分類する
JavaScript
- npm https://docs.npmjs.com/
 - yarn https://yarnpkg.com/lang/en/docs/
 - React https://reactjs.org/docs/getting-started.html
 - AngularJS https://docs.angularjs.org/guide
 - Babel https://babeljs.io/docs/en/
 - gulp https://gulpjs.org/
 - browserify https://github.com/browserify/browserify#usage
 Elastic Stack
- Elasticsearch https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
 - Logstash https://www.elastic.co/guide/en/logstash/current/index.html
 - Kibana https://www.elastic.co/guide/en/kibana/current/index.html
 REST API
- 投稿日:2019-03-23T19:55:33+09:00
 
公式ドキュメントリンク集(Python,JS,API)
延々と足して行く。増えたら分類する
Dev tools(ざっくりだな。。)
名称 説明 URL git 使いにくい https://git-scm.com/doc vagrant virtualbox上にたてて使ってる https://www.vagrantup.com/docs/ docker 負荷試験ぐらいでしか使えてない https://docs.docker.com/ Python
名称 説明 URL pip パッケージ https://pip.pypa.io/en/stable/ pycurl curlできる http://pycurl.io/docs/latest/ hashlib CTFでよくつかう https://docs.python.org/ja/3/library/hashlib.html JavaScript
名称 説明 URL npm パッケージ https://docs.npmjs.com/ yarn パッケージ https://yarnpkg.com/lang/en/docs/ React コンポ https://reactjs.org/docs/getting-started.html AngularJS https://docs.angularjs.org/guide Babel なまえすごい https://babeljs.io/docs/en/ gulp ビルド https://gulpjs.org/ browserify https://github.com/browserify/browserify#usage Elastic Stack
名称 説明 URL Elasticsearch 検索 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html Logstash 処理 https://www.elastic.co/guide/en/logstash/current/index.html Kibana 表示 https://www.elastic.co/guide/en/kibana/current/index.html REST API
名称 説明 URL Virustotal マルウェアのあれ https://www.virustotal.com/ja/documentation/public-api/ Game
名称 説明 URL cocos2d-x ゲームエンジン https://docs.cocos2d-x.org/api-ref/ 
- 投稿日:2019-03-23T19:55:33+09:00
 
公式ドキュメントリンク集(Python,JS,API,Security)
延々と足して行く。増えたら分類する
Dev tools(ざっくりだな。。)
名称 説明 URL git 使いにくい https://git-scm.com/doc vagrant virtualbox上にたてて使ってる https://www.vagrantup.com/docs/ docker 負荷試験ぐらいでしか使えてない https://docs.docker.com/ Python
名称 説明 URL pip パッケージ https://pip.pypa.io/en/stable/ pycurl curlできる http://pycurl.io/docs/latest/ hashlib CTFでよくつかう https://docs.python.org/ja/3/library/hashlib.html JavaScript
名称 説明 URL npm パッケージ https://docs.npmjs.com/ yarn パッケージ https://yarnpkg.com/lang/en/docs/ React コンポ https://reactjs.org/docs/getting-started.html AngularJS https://docs.angularjs.org/guide Babel なまえすごい https://babeljs.io/docs/en/ gulp ビルド https://gulpjs.org/ browserify https://github.com/browserify/browserify#usage Elastic Stack
名称 説明 URL Elasticsearch 検索 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html Logstash 処理 https://www.elastic.co/guide/en/logstash/current/index.html Kibana 表示 https://www.elastic.co/guide/en/kibana/current/index.html REST API
名称 説明 URL Virustotal マルウェアのあれ https://www.virustotal.com/ja/documentation/public-api/ Security
名称 説明 URL pfSense OSSのFW/router https://docs.netgate.com/pfsense/en/latest/index.html VyOS OSSのrouter https://wiki.vyos.net/wiki/User_Guide Game
名称 説明 URL cocos2d-x ゲームエンジン https://docs.cocos2d-x.org/api-ref/ 
- 投稿日:2019-03-23T19:10:19+09:00
 
setterとgetterの実装
JavaScript本格入門(ISBN 978-4774184111)で基礎からJavaScriptを勉強するシリーズです。今回はChapter5からアクセサーメソッドについてです。
アクセサーメソッドは、セッターメソッドとゲッターメソッドを合わせた言い方です。
アクセサーメソッドの実装の仕方と使用方法について勉強したのでまとめます。アクセサーメソッドを使わない実装
let human = { name:"", age:"", } // 使う側(値のセット) human.name = "Giorno Giovanna"; human.age = 15; // 使う側(値のゲット) console.log(human.name); // Giorno Giovanna console.log(human.age); // 15非常にシンプルな実装です。
続いてアクセサーメソッドを用いた実装をしてみます。アクセサーメソッドを使った実装
let human = { set name(value){ this._name = value; }, get name(){ return this._name; }, set age(value){ this._age = value; }, get age(){ return this._age; } } // 使う側(値のセット) human.name = "Giorno Giovanna"; human.age = 15; // 使う側(値のゲット) console.log(human.name); // Giorno Giovanna console.log(human.age); // 15humanオブジェクトの中にset構文とget構文を用いてプロパティを定義してみました。
まずセッターメソッドの動きを見てみます。
1.human.nameに値をセットすると、セッターメソッドset name(value)が呼ばれます
2. セッターメソッドの中では、human._nameというプロパティを新しく作成し、そこにvalueの値を格納します使う側は、
human.nameに値を代入したつもりなのですが、セッターメソッドの動きによって値をhuman._nameという別のところに格納したことになります。次にゲッターメソッドの動きを見てみます。
1.human.nameにアクセスしようとすると、ゲッターメソッドget name()が呼ばれます
2. ゲッターメソッドの中では、human._nameというプロパティの値を戻り値として返します使う側は、
human.nameの値を取得したつもりなのですが、ゲッターメソッドの動きによってhuman._nameという別の値を取得させられます。セッターメソッドとゲッターメソッドの働きによって、間接的に
human._nameの値をやり取りするので、使う側からはhumanオブジェクトの中身がアクセサーメソッドを使って実装されてあろうがなかろうが、値のセットとゲットの方法は変わらないことに注目です。値のセットとゲットにワンクッションあるだけですので、これではあまり何がうれしいのかわかりませんので、セッターとゲッターを使うと便利になる例を紹介します。
例1: プロパティに格納する値のチェックをしたい場合
human.nameに入る値は文字列でないといけないし、human.ageは数値であるべきです。
そのような場合、セッターメソッドにチェックする実装を入れてやることができます。beforelet human = { name:"", age:"", } // 使う側(値のセット) human.name = 15; // 望ましくない値として数値が入ってきた human.age = "Giorno Giovanna"; // 望ましくない値として文字列が入ってきた // 使う側(値のゲット) console.log(human.name); // 15 console.log(human.age); // Giorno Giovanna望ましくない値がそのままプロパティにセットされてしまいます。
afterlet human = { set name(value){ if(typeof value === "string"){ this._name = value; }else{ console.log("nameが文字列じゃないじゃあないか!"); } }, get name(){ return this._name; }, set age(value){ if(typeof value === "number"){ this._age = value; }else{ console.log("ageが数値じゃないじゃあないか!"); } }, get age(){ return this._age; } } // 使う側(値のセット) human.name = 15; human.age = "Giorno Giovanna"; // 使う側(値のゲット) console.log(human.name); // undefined console.log(human.age); // undefined実行結果nameが文字列じゃないじゃあないか! ageが数値じゃないじゃあないか! undefined undefinedセッターメソッドで値のチェックをすることができ、使う側が幾分か安全になりました。
例2: プロパティを読み取り専用にしたい場合
年齢は毎年変わりますが、名前はそう簡単には変わるものではありません。
なので、
human.ageは後から書き換え可能にしたいですが、human.nameは後から変えられないように読み取り専用にしたいとします。beforelet human = { name: "Giorno Giovanna", // もともとの名前 age: 15, // もともとの年齢 } // 使う側(値のゲット) console.log(human.name); // Giorno Giovanna console.log(human.age); // 15 // 使う側(値のセット) human.name = "汐華初流乃"; // 改名! human.age = 16; // 加齢! // 使う側(値のゲット) console.log(human.name); // 汐華初流乃(改名されてしまった。望ましくない) console.log(human.age); // 加齢された(これは望ましい)これでは
human.nameの値が後から書き換えられてしまいます。
アクセサーメソッドを使ってhuman.nameを読み取り専用にしてみます。afterlet human = { _name : "Giorno Giovanna", // もともとの名前 _age : 15, // もともとの年齢 get name(){ return this._name; }, set age(value){ this._age = value; }, get age(){ return this._age; } } // 使う側(値のゲット) console.log(human.name); // Giorno Giovanna console.log(human.age); // 15 // 使う側(値のセット) human.name = "汐華初流乃"; // 改名! human.age = 16; // 加齢! // 使う側(値のゲット) console.log(human.name); // Giorno Giovanna(改名が阻止できた) console.log(human.age); // 加齢された(これは望ましい)改名が阻止できました。
何をしたかというと、nameのセッターメソッドの実装をやめゲッターメソッドだけ持つようにするようにしました。これにより、human.nameは読み取り専用となりました。
human.ageは後で加齢できるように読み書きできるようにセッターメソッド、ゲッターメソッドの両方を持ちます。まとめ
セッターメソッドとゲッターメソッドを使うことで、
1. プロパティに予期しない値が入るのを防ぐこと
2. プロパティの値が後から書き換わることを防ぐこと
ができることがわかりました。ただし、この実装では限界があり、使う側が直接
human._nameやhuman._ageをアクセスしてしまうと、1、2が保証できなくなってしまいます。コーディング規約などでアンダースコア付きのプロパティには直接アクセスしないことをお約束しておく必要があります。
おまけ
クロージャやシンボルを使うともう少し安全なアクセサーメソッドを実装することができます。
以下の記事で紹介されているものがわかりやすいです。
JavaScriptのgetter/setterの使い方を考えよう
- 投稿日:2019-03-23T18:52:09+09:00
 
argumentsプロパティの理解と使用例。
argumentsプロパティたるものと、その使用例を、感覚的に理解するためのメモ。
【前提知識】for...of 文argumentsとは?
- 実引数のこと。
 - 関数を呼び出す際に入力される引数のこと。
 - 実引数は、関数のargumentsというプロパティに、配列の形で代入されている。
 
- 例:第一引数 → arguments[0]
 【使用例】
使用例.jsconst xxx = ()=> { for ( let index in xxx.arguments ) { console.log ( xxx.arguments[index] ); } }; //これで、渡された引数をすべてconsoleに表示することができる。 //map関数の引数バージョンのようなイメージ。 xxx(1,2,3,4,5); //1 //2 //3 //4 //5
- 投稿日:2019-03-23T17:16:51+09:00
 
独自の音声圧縮をJavaScriptで作ってみた
はじめに
今回はMP3、Vorbis(Ogg)、 AAC等の音声圧縮形式が使用している修正離散コサイン変換を使用して音声データの圧縮、伸長をJavaScriptとWebAudioを使用して実装して見ました。
https://redlily.github.io/training-webaudio-compression
設計
設計方針
- JavaScriptとWebAudioで圧縮、伸長、再生が可能な実装を行う。
 - 音声に関わる実装はOSSのライブラリを一切使わずに自力で実装する。
 - MP3、Vorbis(Ogg)、AACの音声圧縮形式が使用している修正離散コサイン変換を用いた実装を行う。
 - 音質をある程度保ちながら16bitで量子化された無圧縮データと比較して1/8程度まで圧縮を行う。
 - なるだけ単純な実装で圧縮率を上げる。(エンコーダ、デコーダの実装をあわせて1000行程度)
 - 今回は音声圧縮のノウハウの獲得が目的なので可逆圧縮の導入は見送り。
 圧縮・再生用のアプリケーションの設計
音声の読み込み、圧縮、伸長、再生を行うアプリケーション部分の設計概要となります。
圧縮
- 音声データを読み込む
 - AudioContex.decodeAudioを使用して音声データを波形データに変換する。
 - 波形データを独自の圧縮形式にエンコードする。
 - ArrayBufferにデータを変換し、ダウンロード可能にする。
 伸長、再生
- 独自の圧縮済みの音声データを読み込む。
 - ScriptProcessorNodeを生成する。
 - 独自の圧縮済み音声データを波形データにデコードする。
 - 波形データをスピーカーに出力する。
 エンコーダ・デコーダの設計
音声の波形データを実際にエンコード、デコードするコーデックの設計概要となります。
エンコード
- 波形データを入力
 - 窓関数を適用
 - 修正離散コサイン変換を適用
 - 周波数を間引く
 - 圧縮済みデータを出力
 デコード
- 圧縮済みデータを入力
 - 間引かれた周波数データを修正離散コサイン変換用の配列に展開
 - 逆修正離散コサイン変換を適用
 - 窓関数を適用
 - 波形データを出力
 データ設計
基本構造
大枠の設計はヘッダーがデータの先頭あり、その後に固定長のフレームの配列が連なるといった単純な構造となります。
ヘッダ
変数名 型 説明 MAGIC_NUMBER UINT32 マジックナンバー、"WAM0"が固定値 DATA_SIZE UINT32 データのバイトサイズ DATA_TYPE UINT32 拡張用のデータタイプ、"SMD0"が固定値 VERSION UINT32 データのバージョン SAMPLING_RATE UINT32 サンプリングレート CHANNEL_SIZE UINT32 チャネル数、1がモノラル、2がステレオ SAMPLE_COUNT UINT32 データに含まれるサンプル数 FREQUENCY_RANGE UINT32 周波数ブロックのサイズ FREQUENCY_TABLE_SIZE UINT32 周波数テーブルのサイズ FRAME_COUNT UINT32 データに含まれるフレーム数 FRAME_DATA FRAME[CHANNEL_SIZE * FRAME_COUNT] フレーム配列、チャネル数が2の場合、左、右とフーレムが並ぶ フレーム
変数名 型 説明 MASTER_SCALE UINT32 このフーレムの主音量 SUB_SCALES UINT4[8] 8つの周波数帯用の音量を調整するためのスケール値 ENABLE_FREQUENCIES 1bit[FREQUENCY_RANGE] 
or
log_2(FREQUENCY_RANGE)-bit[FREQUENCY_TABLE_SIZE]周波数の有効無効を収納した1bitのフラグ配列、もしくは有効な周波数のインデックスを収納した配列 
バイト数の小さい方を使用し4バイトアライメントに適合するサイズにするFREQUENCY_VALUES 4bit[FREQUENCY_TABLE_SIZE] 有効な周波数の対数で符号化された数値 離散コサイン変換(discrete cosine transform)
N個のサンプルデータに対してN個の0からN-1の異なる周波数のcos波に信号を分解する事が出来る変換になります。
JPEGはこの離散コサイン変換を利用してデータの圧縮を行っています。
下記はイメージ図となります。
離散コサイン変換タイプ2(DCT-Ⅱ もしくは DCT)の式
y_k = \sum^{N-1}_{n=0} x_n \cos(\frac{\pi}{N}(n + \frac{1}{2})k)離散コサイン変換タイプ3(DCT-Ⅲ もしくは 逆DCT)の式
x_n = \frac{1}{2} y_0 + \sum^{N-1}_{k=1} y_k \cos(\frac{\pi}{N}(n + \frac{1}{2})k)高速化
離散コサイン変換はN^2のオーダーで計算量が増えてしまう特性があります。そのまま離散コサイン変換を数式通り実装してしまうとかなり遅くなってしまうので高速化アルゴリズムを導入します。
今回はLee型DCTと呼ばれる高速化手法を下記の論文を参考に実装しました。
これを適用する事によりN log Nのオーダーの計算量ですみます。A New Algorithm to Compute the Discrete Cosine Transform - BYEONG GI LEE
離散コサイン変換タイプ2(DCT-Ⅱ)の高速化の実装例
// 離散コサイン変換、タイプII // n - サンプル数、2のべき乗である必要がある // x - n個のサンプルの配列 static dctII(n, x) { // バタフライ演算 let rad = Math.PI / (n << 1); for (let m = n, mh = m >> 1; 1 < m; m = mh, mh >>= 1) { for (let i = 0; i < mh; ++i) { let cs = 2.0 * Math.cos(rad * ((i << 1) + 1)); for (let j = i, k = (m - 1) - i; j < n; j += m, k += m) { let x0 = x[j]; let x1 = x[k]; x[j] = x0 + x1; x[k] = (x0 - x1) * cs; } } rad *= 2.0; } // データの入れ替え FastDCT.swapElements(n, x); // 差分方程式 for (let m = n, mh = m >> 1, mq = mh >> 1; 2 < m; m = mh, mh = mq, mq >>= 1) { for (let i = mq + mh; i < m; ++i) { let xt = (x[i] = -x[i] - x[i - mh]); for (let j = i + mh; j < n; j += m) { let k = j + mh; xt = (x[j] -= xt); xt = (x[k] = -x[k] - xt); } } } // スケーリング for (let i = 1; i < n; ++i) { x[i] *= 0.5; } }離散コサイン変換タイプ3(DCT-Ⅲ)の高速化の実装例
// 離散コサイン変換、タイプIII // n - サンプル数、2のべき乗である必要がある // x - n個のサンプルの配列 static dctIII(n, x) { // スケーリング x[0] *= 0.5; // 差分方程式 for (let m = 4, mh = 2, mq = 1; m <= n; mq = mh, mh = m, m <<= 1) { for (let i = n - mq; i < n; ++i) { let j = i; while (m < j) { let k = j - mh; x[j] = -x[j] - x[k]; x[k] += x[j = k - mh]; } x[j] = -x[j] - x[j - mh]; } } // データの入れ替え FastDCT.swapElements(n, x); // バタフライ演算 let rad = Math.PI / 2.0; for (let m = 2, mh = 1; m <= n; mh = m, m <<= 1) { rad *= 0.5; for (let i = 0; i < mh; ++i) { let cs = 2.0 * Math.cos(rad * ((i << 1) + 1)); for (let j = i, k = (m - 1) - i; j < n; j += m, k += m) { let x0 = x[j]; let x1 = x[k] / cs; x[j] = x0 + x1; x[k] = x0 - x1; } } } }離散コサイン変換の欠点
離散コサイン変換を音声圧縮に使用した場合、サンプルを適当なサイズのブロックに区切って周波数変換をかけて、そのデータに対し非可逆圧縮をかけていく事になるのですが、この方法で非可逆圧縮をかけて元に戻そうとした場合、ブロックとブロックの境で高周波数のノイズが発生してしまいます。
この問題は同じく離散コサイン変換を使用するJPEGでもブロックノイズという形で発生します。音声の場合は聞くに耐えないくらいのノイズが発生するので、この問題に対処する必要があります。
修正離散コサイン変換(modified discrete cosine transform)
離散コサイン変換を音声に適応する上での欠点、変換したブロックとブロックの境界で高周波数のノイズが発生してしまう欠点を窓関数と組み合わせて使用する事により、その欠点を解消することの出来る変換となります。
具体的にはこの変換は解析ブロック半分ずつ重ねて周波数変換を行うことが出来、この重なる部分に対して窓関数をかけてクロスフェードさせる事により解析ブロックと継ぎ目を目立たなくすることが出来ます。
修正離散コサイン変換(MDCT)の式
y_k = \sum^{2N-1}_{n=0} x_n \cos(\frac{\pi}{N}(n + \frac{1}{2} + \frac{N}{2})(k + \frac{1}{2}))逆修正離散コサイン変換(逆MDCT)の式
x_n = \frac{1}{N} \sum^{N-1}_{k=0} y_k \cos(\frac{\pi}{N}(n + \frac{1}{2} + \frac{N}{2})(k + \frac{1}{2}))高速化
今回は離散コサイン変換の高速化処理をそのまま流用できるアルゴリズムを下記の論文を参考に実装しました。
Fast IMDCT and MDCT Algorithms— A Matrix Approach Mu-Huo Cheng and Yu-Hsin Hsu
修正離散コサイン変換の高速化の実装例
// 修正コサイン変換(MDCT) // n - 周波数配列数、2のべき乗である必要がある // samples - 2n個のサンプル配列、この配列が変換処理の入力元となる // frequencies - n個の周波数配列、この配列が変換処理の出力先となる static mdct(n, samples, frequencies) { // データを結合 let ns1 = n - 1; // n - 1 let nd2 = n >> 1; // n / 2 let nm3d4 = n + nd2; // n * 3 / 4 let nm3d4s1 = nm3d4 - 1; // n * 3 / 4 - 1 for (let i = 0; i < nd2; ++i) { frequencies[i] = samples[nm3d4 + i] + samples[nm3d4s1 - i]; frequencies[nd2 + i] = samples[i] - samples[ns1 - i]; } // cos値の変換用の係数をかけ合わせ let rad = Math.PI / (n << 2); let i = 0; let nh = n >> 1; for (; i < nh; ++i) { frequencies[i] /= -2.0 * Math.cos(rad * ((i << 1) + 1)); } for (; i < n; ++i) { frequencies[i] /= 2.0 * Math.cos(rad * ((i << 1) + 1)); } // DCT-II FastDCT.dctII(n, frequencies); // 差分方程式 for (let i = 0, j = 1; j < n; i = j++) { frequencies[i] += frequencies[j]; } }逆修正離散コサイン変換(Inverse MDCT)の高速化の実装例
// 逆修正コサイン変換 // n - 周波数配列数、2のべき乗である必要がある // samples - 2n個のサンプル配列、この配列が変換処理の出力先となる // frequencies - n個の周波数配列、この配列が変換処理の入力元となる static imdct(n, samples, frequencies) { // cos値の変換用係数を掛け合わせ let rad = Math.PI / (n << 2); for (let i = 0; i < n; ++i) { frequencies[i] *= 2.0 * Math.cos(rad * ((i << 1) + 1)); } // DCT-II FastDCT.dctII(n, frequencies); // 差分方程式 frequencies[0] *= 0.5; let i = 0, j = 1; let nh = n >> 1; for (; i < nh; i = j++) { frequencies[j] += (frequencies[i] = -frequencies[i]); } for (; j < n; i = j++) { frequencies[j] -= frequencies[i]; } // スケーリング for (let j = 0; j < n; ++j) { frequencies[j] /= n; } // データを分離 let ns1 = n - 1; // n - 1 let nd2 = n >> 1; // n / 2 let nm3d4 = n + nd2; // n * 3 / 4 let nm3d4s1 = nm3d4 - 1; // n * 3 / 4 - 1 for (let i = 0; i < nd2; ++i) { samples[ns1 - i] = -(samples[i] = frequencies[nd2 + i]); samples[nm3d4 + i] = (samples[nm3d4s1 - i] = frequencies[i]); } }窓関数(windows function)
修正離散コサイン変換のデータの重なった部分を滑らかに結合するために使用します。簡単に言えばクロスフェードさせてデータのブロックとブロックの境を目立たなくするために導入する関数となります。
今回はVorbisで使用されているVorbis窓と呼ばれる窓を使用します。
\omega_x = \sin(\frac{\pi}{2}\sin^{2}\pi x), 0 \leq x \leq 1周波数帯の間引き
人間の耳は相対的に大きな音の近くにある周波数帯の小さな音は感知しにくい特性があります。これをマスキング効果いい、これを利用して修正離散コサイン変換で得られた周波数配列からデータを間引きます。
アルゴリズムとしては等ラウドネス曲線等を利用して各周波数の音量を人間の知覚的に平準化、その後マスキング効果による周波数の選定を行えば、より良い結果が得られるのでしょうが、今回は実装は割愛してわかりやすく周波数帯を適当にぶつ切りにして、そのぶつ切りにした周波数帯の中で最も数値の絶対値が大きい周波数を出力候補としました。
この間引により出力する周波数の数を1/4から1/8程度まで減らしても音質を保つ事が出来ます。
対数による量子化
通常PCMはサンプルデータを線形的な数値で量子化を行いますが、人間は音の知覚が対数関数的である生理学的な特性を利用して線形的に量子化すると16bit程度の容量が必要なデータを音質を保ちながら符号部1bit、指数部3bitの計4bit程度のデータに圧縮する事が出来ます。これは浮動小数点数で言えば仮数部を取り除いたものと言えます。
今回の実装では対数の底は2を使用しますがデータの設計によって底は決めると良さそうです。例えば8bitでデータを保存する場合は底が2だとbitの幅に対して数値の精度が荒くなったりします。
エンコードの例
y_n = -(\log_2 \frac{|x_n|}{2^{15}})\\ s_n = sgn(x_n)encodedFrequencies[i] = -Math.log2(Math.abs(inputFrequencies[i]) / (1 << 15)); frequencySigns[i] = inputFrequencies[i] < 0 ? -1 : 1;デコードの例
x_n = 2^{15} \times 2^{-y_n} \times s_noutputFrequencies[i] = (1 << 15) * -Math.pow(2, -encodedFrequencies[i]) * frequencySigns[i];スケール値を適用
対数による量子化は音量の大きな音には良いのですが音量が小さな音に対しては音声が歪んでしまいます。
そこで各周波数の最大値をスケール値としてデータに保持します。これは浮動小数点数で言えば仮数部に相当する数値になります。エンコードの例
y_n = -(\log_2 \frac{|x_n|}{scale})\\ s_n = sgn(x_n)encodedFrequencies[i] = -Math.log2(Math.abs(inputFrequencies[i]) / scale); frequencySigns[i] = inputFrequencies[i] < 0 ? -1 : 1;デコードの例
x_n = scale \times 2^{-y_n} \times s_noutputFrequencies[i] = scale * -Math.pow(2, -encodedFrequencies[i]) * frequencySigns[i];サブスケール値を適用
対数による量子化により音量の大きな音、小さな音に対応出来るようになりましたが各周波数の精度は周波数全体の最大値に左右されてしまいます。つまり最大値の周波数の音質は良好なものになるのですが、それ以外の周波数帯の音質は有効な数値が小さい分、劣化します。
例えば比較的静かな状態で音量が大きな低音と音量が少し低い高音が同時になっているような場合に高音の周波数帯の音質が低下が顕著になってしまうといったものになります。
そこで各周波数でバンドを区切り、スケール値の補助的な数値を保持します。ここでは対数の数値オフセットを対数化されたサンプルデータに適用することにします。周波数バンドの区切り方は比較的重要なデータが多い低周波数は密し、高周波数に行くにつれ範囲を大きくとるようにしました。
エンコード時
y_n = -(\log_2 \frac{|x_n|}{Scale}) + sub_k\\ s_n = sgn(x_n)encodedFrequencies[i] = -Math.log2(Math.abs(inputFrequencies[i]) / mainScale) + subScale[j]; frequencySigns[i] = inputFrequencies[i] < 0 ? -1 : 1;デコード時
x_n = scale \times 2^{-y_n - sub_k} \times s_noutputFrequencies[i] = mainScale* -Math.pow(2, -encodedFrequencies[i] - subScale[j]) * frequencySigns[i];出来上がったもの
UIが貧弱ですが上記のものを全て実装したものがこちらになります。
↓実際に動作するもの
https://redlily.github.io/training-webaudio-compression
デフォルトの設定で48000Hz、ステレオのデータを周波数、チャネル数を変えずに且つ音質もそこそこ保ったまま、同じ条件のwav形式の無圧縮データと比較して1/8程度のビットレート170kpbs程度のデータ量に圧縮する事が出来ます。
AudioContext.decodeAudioの機能でwav形式の他にMP3、Vorbis、AACとブラウザが対応していれば、どんな形式でも圧縮対象のデータとして読み込むことが可能ですが、wav形式の使用が推奨です。
感想としてはMP3等の既存の修正離散コサイン変換を利用した音声圧縮には劣るものの個人で設計し実装した割には音質を保って圧縮できるものが出来たかと思っています。
機能
- 圧縮対象のデータ読み込み
 - 圧縮済みのデータの読み込み
 - 圧縮オプションの選択
 
- ステレオ、モノラルの選択
 - サンプリング周波数の選択
 - 処理サンプル数の選択
 - 周波数帯の本数の選択
 - データの圧縮
 - 圧縮済みデータの再生
 参考
- 離散コサイン変換
 - 修正離散コサイン変換
 - 高速離散コサイン変換
 - 高速修正離散コサイン変換
 - 心理音響学
 成果物
- GitHub
 - サンプルプログラム
 デコーダ、エンコーダの実装の細かい詳細は、この記事の中で書ききれないので知りたい方は上記のソースコードを参照してくれれば有り難いです。
- 投稿日:2019-03-23T16:09:49+09:00
 
【CSS/Javascript】手書き風の文字を錬成して時代錯誤に立ち向かえ
TL;DR
- 手書き文化は滅べ
 - それっぽく対抗してみた
 - 実運用は自己責任で…
 intro
わし「ES提出したるで~、OpenES(※)でいくらでも出したるわ」
企業「手書きね^^」
わし「」こういう非効率の塊みたいな企業が死滅することを祈りながら、技術的に解決することを試みる。
※OpenES: Web上で書いてそのまま提出できるES。ガクチカ(学生時代に力を入れていたこと)という9割の人間はろくに書けない質問などを提供してくれる
目標
ぱっとみ手書きっぽくないようなフォントの組み合わせとかを錬成。
使用フォント
ダーツフォント
- http://www.p-darts.jp/font/dartsfont/
 - ボールペンで書いたような細いフォント(公式ページより)
 
- 見てもらうとわかるが、字が綺麗
 font-weight: boldじゃないとめっちゃ細いKalam
- https://fonts.google.com/specimen/Kalam?selection.family=Kalam
 - Google Fontから適当に拝借
 - …したいところだが、そのままだと文字の太さバランスが合わないので少し調整が必要
 - ダーツフォントの方に文字幅を合わせるので、英語主体の文章だと違和感はある
 
- 気になるならcssを分離したほうがいい
 1: それっぽいフォントを組み合わせる
CSSを整備する。
@font-face { font-family: 'Kalam'; font-weight: bold; /* ここをboldに指定することで、標準の太さフォントを太字と誤認させる */ src: local('Kalam'), local('Kalam-Regular'), url('./fonts/kalam/kalam-v9-latin-regular.woff2') format('woff2'), url('./fonts/kalam/kalam-v9-latin-regular.woff') format('woff'); } @font-face { font-family: 'dartsfont'; src: local('dartsfont'), url('./fonts/dartsfont/dartsfont.eot?#iefix') format('eot'), url('./fonts/dartsfont/dartsfont.woff') format('woff'); } /* 手書き風 */ .hw { font-family: 'Kalam', 'dartsfont'; font-weight: bold; letter-spacing: -1px; /* そのままだと若干幅が広い。お好みで */ text-shadow: 0 0 1px #EEE; /* 影をつけると文字が濃く見える。好み */ color: #222; /* ここもお好み */ transform: rotate(0.05deg); /* Windows Chromeできれいに描画してもらうため */ }フォントは
cssの中身見て適宜配置。これでひとまずそれっぽくなる。この他に、行間とかを調整するために
pを修飾する。p { white-space: pre-line; /* コピペできるように */ font-size: 1.4rem; /* 文字サイズ。任意 */ line-height: 1.3; /* 行間。任意 */ line-break: strict; /* 禁則処理。あったほうが自然 */ text-align: justify; /* 両端揃え。これも多分あったほうがいい */ }これで準備1は完了。
以上のCSSを使用して、文章をHTMLで書いてみるとこんな感じで表示される。
(文章は適当にここから拝借)
わりとそれっぽい。
半角数字は全体的に詰まってみえるため、1文字なら全角を使うことを推奨。
(上の画像でいうと「学生1位」の部分)2: ランダム性を導入する
コード
このままだとPCで出力した感がまだ残っている。
というのも、各フォントごとの文字の形が全く同じだからである。これを解消するのに
Javascriptを使用する。
jQueryとsugarjsを使用して、こんな感じで書いてみた。Sugar.extend(); $(() => { var hws = $(".hw"); hws.each((i,e) => { console.log(e.textContent.split('')); e.innerHTML = e.textContent.split('').map(t => { if(t === '\n') return `<br/>`; if(t === '\t') return ``; return `<span style="${generateRandomizeStyle()}">${t}</span>`; }).join(""); }); }); function generateRandomizeStyle(){ const CharBeautyRate = 500; // 文字の綺麗さ指数。だいたい100-1000の範囲 var color = Number.random(0, 0x30); var colorRgb = [1,1,1].map(e => color); var tax = 1 + Number.random(-10, 10) / CharBeautyRate; var tby = 1 + Number.random(-10, 10) / CharBeautyRate; var tay = Number.random(-10, 10) / CharBeautyRate; var tbx = Number.random(-10, 10) / CharBeautyRate; var transfromLocate = [1,1].map(e => Number.random(-5, 5) / 10); var letterSpace = Number.random(-8, -5) / 5; return ` display: inline-block; white-space: pre; color: rgb(${colorRgb}); letter-spacing: ${letterSpace}px; transform: matrix(${tax},${tay},${tbx},${tby},${transfromLocate}); `; }各文字ごとに
<span>で囲み、それぞれについてランダムで少し文字を変形させる。
このとき、あんまり派手に変形させると変な文字になるので、微小にずらしている。
調整しているパラメーターは「色」「文字空白」「文字形状」の3つ。文字形状の調整
色、空白はランダム化させるだけでいいが、形状はそこまで単純でもない。
今回は、transform:matrixを使用した。
matrixは行列形式で文字変形を指定する。
詳しくはググってもらうのが早いが、簡単に説明すると
matrix(a, b, c, d, e, f)と指定した場合、前半のa~dの部分が行列になる。\begin{matrix} a & b \\ c & d \end{matrix}一切の変換を施さない行列はというと、
\begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix}になる。
今回は少しだけ動かしたいので、\begin{matrix} 1+δw & 0+δx \\ 0+δy & 1+δz \end{matrix}といったようにパラメーターを微小に動かす。
ここの値の動かし度合いで字の汚さを簡易的に指定することができる。先程のコードでいうと
var tax = 1 + Number.random(-10, 10) / CharBeautyRate; var tby = 1 + Number.random(-10, 10) / CharBeautyRate; var tay = Number.random(-10, 10) / CharBeautyRate; var tbx = Number.random(-10, 10) / CharBeautyRate;の
CharBeautyRateの部分である。サンプル例
上記コードを当てはめると、こんな感じの文字になる。
CharBeautyRate=50ぐらいになるとどういった変形を施しているかが明確になる。
徐々に文字が変な形になることがわかるだろう。
手書き風かつ丁寧な文章にしたいので、200-500ぐらいが無難だろうか。今回は
Number.randomで一様乱数を使っているが、正規分布に従わせるとよりそれっぽくなりそう。demo
つくりました。
https://arika0093.github.io/handwriting/tools.html課題
- フォントの太さが均一
 
text-shadowでうまいこと調整できるか- ボールペン字ならそこまで気にならないか
 - とめはね等の調節
 
- さすがに厳しい
 - 文字変形の単純さ
 
- うまい方法があまり思いつかない
 - 字の「癖」の再現
 
transform:matrixを一様乱数でなくある程度の傾向をつける等?- 実際のESに貼り付ける方法
 
Word等で位置を調節して印刷が一番無難?- いつ使うのか
 
- どうでもいい企業にしか使えないよね…
 参考文献
https://xar.sh/post/95166529739/
https://sugarjs.com/docs/#/Number/random
https://qiita.com/junya/items/a1ad6126fa0315acc2aa
https://ginpen.com/2018/11/13/understanding-transform-matrix/
https://understanding-transform-matrix.ginpei.info/
- 投稿日:2019-03-23T16:07:34+09:00
 
React Static 公式ドキュメント和訳 「基礎概念」編
React Static とは
Reactベースの静的サイトジェネレータです。
つまり、全てハードコードの静的サイトはもちろん、ブログのようなCMSベースのサイトも
- React+αの知識で!
 - DBなしに!
 - サーバーの(大した)設定もせず!
 - 超高速表示に!
 作れる優れもの。
僕のようなフロントエンドに知識が偏ってる人間には特に福音だったりします。その中でもReact Staticは、Mediumで3,000clapを叩き出した記事 「2019年のReactジェネレータ」でもGatsbyに続き2番手に選ばれたイケてる子!
しかもGatsbyよりも学習コスト≒React+αのα部分が少ないと僕の中で噂に。ということで公式ドキュメントの「基礎概念」(Core concepts)部分を以下に訳します。
続編 React Static 設定大全 https://qiita.com/IYA_UFO/items/b01ca2eb1ec0082c4b79
MIT License
Copyright (c) 2013-present, Nozzle, Inc.
https://github.com/nozzle/react-static/blob/master/LICENSE
概要
React Staticは他の多くのReactベースの静的サイトジェネレータとは異なります。データから静的ファイル、さらにはプログレッシブに強化された(progressively enhanced)Reactアプリケーションに至るまでのとても自然なデータの流れを持っています。これにより、「データ」と「テンプレート」の関心の分離を手軽に行えます。また、データとテンプレートを可能な限りはっきり分離し、React自身がそうであるように、データの写像としてのサイトを、1つの流れの中でビルド・視覚化することができます。
開発中に起きること
- サイトに必要な全てのデータは、事前に
 static.config.jsに好きな方法で集められます。取得元はマークダウンファイル、ヘッドレスCMSs、GraphQLのエンドポイントからなどなど自由です。データはビルド段階でコンパイルされます。- ページは1つのReactコンポーネントをexportするファイルとして定義され、必要なときにレンダリングされます。
 pages内のファイルは自動的にルーティングされます。- ページコンポーネントを指定して、静的なルーティングを設定することも可能です。
 - React Staticのコンポーネントにある
 RoutePropsやSitePropsを使ってルートごとのデータを取得しページをレンダリングすることができます。これらのコンポーネントのHOC版も利用できます。- 以上を設定すれば、React Staticは正確に、スピーディーに全ページを出力します。
 クライアントサイドで起きること
- 最初のロードでは、最速でページを表示するために最低限のアセットだけがダウンロードされます。これには、ページ特有のHTMLと、ビルド時にエクスポートされた全てのCSSが含まれます。
 - そのページに同期的に必要なデータがHTMLから抽出されます。
 - ReactがHTMLにアプリケーションをマウントします
 - サイトの残りの部分は、ページ遷移が起こるたびにpreload・キャッシュされ、遷移は即座に起きているように見えます。
 コード・データの分割
React Staticはとてもユニークで素晴らしいやりかたで、各ページに必要な最小限のデータをピッタリのタイミングでリクエストします。React Staticは以下の要素に従ってコードとデータを分割します。
ページテンプレート
static.config.jsにルートを書いておくだけで、React Staticは内部的・自動的に各ルート用のテンプレートを分割します。ページデータ
各ルート用の
getData関数の結果が、そのページ専用のJSONファイルとしてHTMLの隣にexportされます。これで9割のケースでデータをうまく分割できます。また、複数のページで何度もアクセスされるデータなどについてさらに最適化したい場合は、以下で説明するsharedDataとcreateSharedDataの2つのAPIでより詳しい操作が可能です。サイトデータ
多くのルートで必要なデータは、
config.getSiteData関数に渡すことで全てのページからアクセスできるようになります。react-universal-componentを使った手動のコード分割
React Staticはデフォルトで
react-universal-componentをサポートしています。つまり、React Staticが持つ自動コード分割に加え、必要であれば手動で巨大なコンポーネントを分割することができます。動的インポートの例を見てください。簡単です!ページ共有データ(上級者向け)
ほとんどのプロジェクトでは必要ありませんが、稀に「全てのページで使うわけではないが、複数のページで全く同じデータを使う」場合があります。その対応には、ページ共有データAPIを使って複数ルートで同じデータを1つのJSONファイルとして共有することができます。例はこちら
ユニバーサルな、「Nodeセーフな」コードを書く
React StaticはブラウザとNode(ビルド中)の両方で動くため、コードの全てが「ユニバーサル」、言い換えれば「Nodeセーフ」であることがとても重要です。私達の多くはブラウザでJavaScriptを書くことになれているので、以下のような点に注意が必要です。
window、documentやブラウザAPIを利用する場合、利用の前に存在チェックをしてください。最も簡単な方法は、これらを利用するコードをcomponentDidMountの中に書くか、if文の中に書くことです。if (typeof document !== 'undefined') { // documentオブジェクトを使う }
window、documentやブラウザAPIに依存するライブラリがNode環境でインポートされないようにしてください。これらのライブラリの一部はブラウザのオブジェクトをすぐに必要とするので、ビルド時にエラーが出ます。エラーを解消するには、スタブを用意して条件分岐で内容をrequireしてください。let CoolLibrary = {} // Nodeで動かす必要があるコードではこのスタブを利用する. if (typeof document !== 'undefined') { CoolLibrary = require('cool-library').default }環境変数
色々試すなかで、特定の環境変数が必要になるかもしれません。以下がReact Static全体で利用できます。
process.env.REACT_STATIC_ENV以下のどれかになります
- production - webpackで本番用にビルド中
 - development - webpackで開発用にビルド中
 - node - nodeでSSR用にビルド中
 本番用のビルド
本番用ビルドの前に、いくつか追加で準備することをおすすめします
static.config.jsにsiteRootを追加してください。siteRootによってReact Staticは絶対パスのリンクを最適化します。また、もしもアプリケーションがhttps://mysite.com/my-static-site/などルート以外の場所で動作する場合も、この設定により普通に機能するようになります。react-static build --stagingを使って、ローカルで本番ビルドをテストしてください。このコマンドでは、本番用のビルドを行いますが、特別にlocalhostで普通に見られるようになります。- 本番ビルドでバグを見つけたら、ビルドコマンドに
 --debugをつけてコードの圧縮を停止できます。ビルドの準備ができたら、
react-static buildで本番用ビルドを開始してください。本番用のファイルはdistファイル、またはあなたがカスタム設定したフォルダに出力されます。このフォルダの中身をホストにアップロードしてください。継続的インテグレーション
サイトが頻繁に更新される場合、何らかのサービスを使って継続的インテグレーションを設定すると良いかもしれません。よくあるのは、NetlifyとそれにリンクしたGithubリポジトリの組み合わせです。これにより、コードが変更された時に自動でサイトを再ビルドすることができます。素晴らしい!
カスタマイズ可能なホスティングサービスを探している場合、Travis CIを使ってカスタマイズされた場所にデプロイするのも良いでしょう。可能性は無限大!ホスティング
過去、静的サイトのデプロイがこんなに簡単だった時代はありません。静的サイトを安く、または無料でホストできるサービスがたくさんあります。実際これは静的サイトの最大のメリットの1つでもあります。つまり、サーバーのメンテナンスが不要で、スケーラビリティをあまり心配しなくて良いのです。以下はおすすめのサービスです。
CMSを使う
CMSはサイトの整理や更新にとても便利です。React Staticチームのお気に入はGraphCMS、Contentful、
Netlify CMSですが、 https://headlesscms.org/ (React Staticで作られています)で自分に合うものを選んでも良いでしょう。
Webhookで再ビルドする
CMSをつかう場合、CMSが変わったときサイトをビルドし直したいな、と考えると思います。
Webhookを使いましょう!ほとんどのモダンなCMSはWebhookを提供します。これらは、単純にCMSに変更があったときにpingされるURLです。CIツールやホスティングサービスに自動リビルドさせるのに使うのが効果的です。例:
404エラーのハンドリング
React Staticで404ページを作るのは簡単です。サーバーによっていくつかの異なる方法で設定できます。
404.jsReactコンポーネントをpagesに置く- 以下のルートを設定する
 { path: '404', component: 'path/to/your/404/component.js' }404コンポーネントはどう使われるか
- 404 コンポーネントはビルド時にルートの
 404.htmlファイルとして出力されます。多くのサーバーはルートが存在しない時に自動的にこのファイルを利用します。- もし
 <Routes />コンポーネントがレンダリングされて、マッチするルートやテンプレートがない場合、404コンポーネントが表示されます。動的ルーティング
訳者がよくわからないのでスキップ
https://github.com/nozzle/react-static/blob/master/docs/guides/dynamic-routes-reach-router.mdWebpackのカスタム設定とプラグイン
React StaticはReact用に調整された素晴らしいデフォルトのWebpack configを持っています。これだけでほとんどの場合は十分なはずです。しかし、設定を変えたくなったら
node.api.jsファイルを設置してwebpack APIで拡張することができます。ページネーション
ページネーションガイドをお読みください!
ブラウザサポート
React StaticはReact自体のサポートブラウザとあなたが選ぶBabelのpolyfillに依存してサポートの範囲を決めます。
- モダンブラウザ(Chrome, Firefox, Safari)の最新版はデフォルトでサポートされています。
 - IEはサポートできますが、
 babel-polyfillをが必要です。
static.config.jsを拡張してIEに対応させるには、まずはbabel-polyfillをインストールしてください。その後、以下のオブジェクトを
static.config.jsのエクスポートに追加して、既存のwebpack設定を拡張してください。webpack: (config, { stage }) => { if (stage === 'prod') { config.entry = ['babel-polyfill', config.entry] } else if (stage === 'dev') { config.entry = ['babel-polyfill', ...config.entry] } return config },
- 投稿日:2019-03-23T14:55:22+09:00
 
文字列の中にある全ての並んだパターンを作る
タイトルって難しいな...
やりたいこと
abcabcの中から
abcabc, abcab, bcabc, abca, bcab, cabc,...といった感じにパターンを作りたい。
結論
var str = "abc".repeat(2); var arr = [] for (var i = 0; i < str.length; i++) { for (var c = 0; c <= str.length - (str.length - i); c++) { if (str.length - i <= 1) { continue; } arr.push(str.substr(c, str.length - i)); } }3行目の
for (var i = 0; i < str.length; i++) {のiの初期値を1にすると最初の
abcabcというただの元の文字列が除外できる。
- 投稿日:2019-03-23T14:45:31+09:00
 
【JavaScript】if命令による条件分岐
if命令でできること
if命令によって、「もし〇〇ならば✕✕を行う」というように、一定の条件を満たすか否かに応じて実行する処理を変える(分岐させる)ことができます。
条件を満たす場合の処理を指定する - if -
if命令の中に与えられた条件式の真偽値がtrue(真)の場合、指定した処理が実行されます。
See the Pen if-1 by OSHMVTRV (@oshmvtrv) on CodePen.
変数iは14であり、条件式「i >= 10」を満たす(真偽値がtrueである)ため、処理が実行され「iは10以上です」と表示されています。仮に変数iが10未満の場合、条件式を満たさないため処理は実行されず何も表示されません。
条件を満たさない場合の処理を指定する - else -
条件を満たす場合だけでなく、満たさない(真偽値がfalseである)場合の処理も指定したい場合は、elseを使うことで処理を実行できます。
See the Pen else-1 by OSHMVTRV (@oshmvtrv) on CodePen.
変数iは8であり、条件式「i >= 10」を満たさないため、「iは10以上です」は表示されません。しかしelseを使って指定した処理は実行され「iは10未満です」と表示されています。
分岐を追加する - else if -
ifとelseのみでは2つしか処理を分岐させるとこができませんが、else ifを使って分岐を追加することができます。
See the Pen else if-1 by OSHMVTRV (@oshmvtrv) on CodePen.
変数iは8であり、条件式「i >= 10」を満たさないため、「iは10以上です」は表示されません。しかしelse ifを使った条件式「i >= 5」は満たすため、指定した処理は実行され「iは5以上です」と表示されています。
※処理が実行される順番
複数の条件式を満たす場合、実行されるのは一番最初に条件を満たした処理のみです。if命令は記述する条件式の順番にも注意が必要です。
See the Pen else if-2 by OSHMVTRV (@oshmvtrv) on CodePen.
複数の条件式のうち、2番目の「i >= 3」と3番目の「i >= 5」を満たしますが、記述上最初に「i >= 3」を満たすため「iは3以上です」と表示されています。
- 投稿日:2019-03-23T14:25:32+09:00
 
$.ajaxでクロスドメイン対応(IE9)
アプリが動作する別のサーバにリクエストを投げた際、ChromeやIE11などのブラウザでは問題なく動作したのですが、IE9で上手くいかなかったことがありました。その際の対応を記しております。
CORS
Cross-Origin Resource Sharingの略。通常XMLHttpRequestは Same-Origin Policyに従います。
ですので、http://hoge-a.comで提供されているアプリケーションのフロントエンドJavaScriptから、XMLHttpRequestでhttp://hoge-b.com/addへのリクエストは別オリジンへのアクセスとなり、制限されます。
オリジン間でこのようなリクエストを許可したい場合、サーバ側のレスポンスヘッダにAccess-Control-Allow-Originで許可するオリジンを指定します。
参考:オリジン間リソース共有 (CORS)
IE9で上手くいかない
今回直面したケースは、フロントエンドJavaScriptから
$.ajaxを使って別オリジンに対してXMLHttpRequestを投げるというものでした。サーバ側にはAccess-Control-Allow-Originを指定して、Chrome, IE11でレスポンスが帰ってくることを確かめました。しかしIE9で実施するとレスポンスが返ってこない...対応
jQuery.support.cors = true;ブラウザがXMLHttpRequestを生成でき、そのオブジェクトがwithCredentialsプロパティを持っていればtrueです。 corsがサポートされていない環境で、クロスドメインXHRリクエストを許可し、クロスドメインリクエストを実行するには $.support.cors = true;を行なってください。
参考:$.support | jQuery 1.9 日本語リファレンス | js STUDIO
CORSがサポートされていないブラウザで別オリジンへのXMLHttpRequestを実行する際は、コード内で上記を含める必要があります。対応後、IE9でもレスポンスが返ってきました!
- 投稿日:2019-03-23T13:52:13+09:00
 
文字が要素の配列で重複していない文字だけ取り除く
- 投稿日:2019-03-23T12:53:23+09:00
 
TypeScript と webpack で作る npm パッケージ
はじめに
TypeScript と webpack を使って npm パッケージを作成して publish する方法を紹介します。実際に npm パッケージを publish する際に考慮しておいたほうがよい TypeScript や webapck の設定については省略しているので悪しからず。
環境
- Node.js 10.13.0
 - npm 6.4.1
 - TypeScript: 3.3.4000
 - ts-loader 5.3.3
 - webpack 4.29.6
 package.json ファイルの作成
以下のコマンドで package.json ファイルを作成します。
npm init次の項目の入力を求められますが、すべて後で変更可能なので気軽に決めて OK です。 ただしパッケージ名は重複不可なので、既に同じ名前のものが存在しないか確認しておいた方がよいでしょう。
- package name
 - version
 - description
 - entry point
 - test command
 - git repository
 - keywords
 - license
 パッケージのディレクトリ構成
特に決まりはありませんが、ここでは例として次のような構成で説明します。
. ├── dist // ビルド後の成果物の出力先 ├── package.json └── src // ソースコードwebpack を使ったビルド処理
まず webpack と webpack-cli をインストールします。
npm install --save-dev webpack webpack-cli次に webpack の設定ファイルを作ります。
モジュールの定義方法によって設定内容は異なりますが、今回は UMD で作ることにします。
libraryに指定した名前はブラウザ上で実行する際のグローバル変数名となります。ここではCalcとしましたが任意です。なおglobalObjectについては注釈を見てください。1webpack.config.jsconst path = require('path'); module.exports = { mode: 'development', entry: './src/index.js', output: { filename: 'index.js', path: path.resolve(__dirname, 'dist'), library: 'Calc', libraryTarget: 'umd', globalObject: 'typeof self !== \'undefined\' ? self : this' } };次に src/index.js を用意します。ここでは例として次のような内容にします。
src/index.jsexport function sum(a, b) { return a + b; }ビルド処理を package.json に記述します。
diff --git a/package.json b/package.json index 77904e2..9810380 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "npx webpack --config webpack.config.js" }, "repository": { "type": "git",試しにビルドしてみましょう。正常にビルドできれば次のような表示がされるはずです。
npm run build ... > npx webpack --config webpack.config.js Hash: e08c8cfaa6ee7d9b3aae Version: webpack 4.29.6 Time: 94ms Built at: 2019-03-23 08:57:52 Asset Size Chunks Chunk Names index.js 956 bytes 0 [emitted] main Entrypoint main = index.js [0] ./src/index.js 28 bytes {0} [built]ソースコードを TypeScript で書けるようにする
TypeScript と ts-loader をインストールします。
npm install --save-dev typescript ts-loader次に tsconfig.json ファイルを用意します。ここで設定内容を変更しても構いませんが、ひとまずはデフォルト設定のままでも OK です。
npx tsc --init次に webpack の設定を修正します。
diff --git a/webpack.config.js b/webpack.config.js index 8cd9058..9d35ec9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,7 +2,15 @@ const path = require('path'); module.exports = { mode: 'development', - entry: './src/index.js', + entry: './src/index.ts', + resolve: { + extensions: [".ts", ".js"], + }, + module: { + rules: [ + {test: /\.ts$/, loader: 'ts-loader'}, + ], + }, output: { filename: 'index.js', path: path.resolve(__dirname, 'dist')entry に指定するファイルの拡張子を変更しているので、ファイルもリネームしておきます。
mv src/index.js src/index.tsこれでソースコードを TypeScript で書くことができるようになっているはずです。試しに src/index.ts を次のように書き換えてみます。
src/index.tsexport function sum(a: number, b: number) { return a + b; }再度ビルドして出力されたファイルを確認すると src/index.ts に書いた内容が出力されていることがわかります。
npm run buildtail -n 10 dist/index.js /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nfunction sum(a, b) {\n return a + b;\n}\nexports.sum = sum;\n\n\n//# sourceURL=webpack://Calc/./src/index.ts?"); /***/ }) /******/ }); });npm パッケージのエントリーポイントとなるファイルを更新する
ここまでで dist/index.js にビルドされた JavaScript が出力されるようになりました。このファイルが npm パッケージのエントリポイントとなるように package.json を修正します。
diff --git a/package.json b/package.json index 1b982a9..593a3d5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "version": "1.0.0", "description": "", - "main": "index.js", + "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "npx webpack --config webpack.config.js",パッケージの公開前のビルド処理を定義
用意したビルド処理を npm パッケージとして publish する前に行う処理として定義します。 npm-scripts の prepare として定義することで publish する前にビルド処理を行い、生成された成果物をパッケージに含めることができます。
diff --git a/package.json b/package.json index 1a5ce7e..1b982a9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "npx webpack --config webpack.config.js" + "build": "npx webpack --config webpack.config.js", + "prepare": "npm run build" }, "repository": { "type": "git",パッケージの公開
まだ npm のアカウントを持っていなければココから作ります。
作成したアカウントでログインします。
npm loginあとは以下のコマンドでパッケージを公開することができます。テストや Linter などを用意している場合は事前に実行するなどして正常に動作することを確認しましょう。
npm publishバージョンの更新
Semantic Versioning に従って更新するのが一般的です。
- API に後方互換性のない変更がある場合にはメジャーバーションを更新
 - 後方互換性のある機能追加の場合にはマイナーバーションを更新
 - 後方互換性のあるバグ修正の場合にはパッチバーションを更新
 npm のサブコマンドとしてそれぞれ以下のコマンドが用意されているので、変更内容に合うものを使います。
npm version major npm version minor npm version patch実行すると package.json, package-lock.json 内に記述された version プロパティが更新されます。また Git リポジトリであるならばバージョンと同名のタグが作成されます。
パッケージの公開時と同様に、再度 npm publish することでバージョンを更新することができます。
npm publish
2019-03-23 現在、 UMD で出力する際に起きる問題の回避措置です。将来的には必要なくなっている可能性があります。 ↩
- 投稿日:2019-03-23T10:44:25+09:00
 
【jQuery 】イベント、フォームに入力した文字を数える、$(this)の用法
TECH::EXPERTの応用カリキュラムを進めていて最初につまづいたポイントです。
「問題はHTMLファイルに適当なフォームを追加して入力した文字数を表示しましょう!!」というもの
この記事ではjQueryでの記述で
イベントがなんなのか
$(this)が何を示しているのか
を理解できると思います。書いたコードはこちら
sample.html<form> フォーム:<input type="text" name="name" id="input-text"> </form> <div id="char-count"> 0文字 </div>sample.js$(function() { $("#input-text").on("keyup", function(){ var charNum = String($(this).val().length); $("#char-count").text(charNum + "文字"); }); });解説:
$("#input-text").on("keyup", function(){ 処理 });ここではHTMLファイル内のid="input_text"に対して.onメソッドで"keyup"というイベントが発生した時にする処理を記述しています。
ここでのfunction()は無名関数と呼ばれ、1回しか呼び出す必要がないため特に関数名を指定していません。
関数の中
String($(this).val().length);
メソッド 処理 String() 処理した後、文字列を返す $(this) $("#input-text")と同値、イベント発火元の要素 .val() メソッドを適用している要素のバリューを返す .length 要素の数を返す input_text要素のバリューの数を文字列として返しています。
例えば、フォームに「おはよう」と記述すれば変数charNumには「4」が代入される訳です。
最後に
$("#char-count").text(charNum + "文字");
メソッド 処理 .text 要素内のテキストを置き換える イベントが発生するたびに、フォームの下に「〇〇文字」と表示しています。
以上で処理の解説は終了です!!
ここまで読んでいただきありがとうございました。
こういった基本動作をたくさん使って動的なページを作れるようにこれからも学習を続けて行きます。
- 投稿日:2019-03-23T08:02:56+09:00
 
Flowtypeのバージョンアップを難なくこなすために型アノテーションを理解する(React Hooksの導入にも)
React + Redux + React Routerを導入したSPAアプリケーションで、Flowのバージョンを上げるのに少し苦労したのでその知見を共有します。
Flowバージョンが0.84以下でReduxを採用しており、Flowのバージョンアップをした時にほぼ必ず起こるエラーですが、意外と英語情報を含めてまとまった解説がなかったのでお役に立てればと思います。
Flow 0.85からexport時にアノテーションが必須となった
React Hookを使うべくReactとFlowのバージョンを上げ、意気揚々と動作確認をしようとしていたところ、Redux周りで大量のFlowエラーが検出される…なんてことがこれから起こるかもしれません。
既存プロジェクトでFlowのバージョンが0.84以下を採用している場合、React Hooksを使うにはFlowのバージョンを0.87以上に上げる必要があります。
しかしFlowの0.85から既存コードにエラーが検出されうる変更が加えられているので、その内容を抑えておく必要があります。
詳しい変更内容は以下のリンクにあるのですが、英語情報なので要約しながら解説していきます。
- Asking for required annotations既存コードにエラーが発生するのに主に「ジェネリック型にアノテーションを付与しないままexportした時」です。「何を言っているのか分からない」という方もいるかもしれませんが、これさえ理解できれば全て解決するので少しだけ頑張って読み進めてください。
そもそもジェネリックとは型を動的に設定するもので、Javaではおなじみですが、FlowやTypeScriptでも重宝されています。例えば以下のようなクラスがあったとします。
class Demo<T> { x: T | null = null; get(): T { if (this.x == null) { throw new Error("unset"); } return this.x; } set(x: T) { this.x = x; } }この時
Tという型が一意に存在するのではなく、string型でもnumber型でも一貫した値を使っていれば、flowが適切に型チェックを行なってくれます。const demo = new Demo(); demo.set('hoge'); const val1 = demo.get(); // setでstring型を指定しているので、getは自動的にstring型になるしかしこのままインスタンスをexportするとflowエラーが出てしまいます。
const demo = new Demo(); demo.set('hoge'); export { demo };14: const demo = new Demo(); ^ Missing type annotation for `T`. `T` is a type parameter declared in `Demo` [1] and was implicitly instantiated at new `Demo` [2]. References: 3: class Demo<T> { ^ [1] 14: const demo = new Demo(); ^ [2]なぜexportした途端にエラーが出てしまうのでしょうか。
型アノテーションをつける理由とは
先程掲載した記事には、アノテーションが要求される要因として「型を正確に推測すること」、そして何より「パフォーマンスの大幅な向上」が挙げられています。
ジェネリックの型が確定しないままexportされると、その依存元に至るまでを全ての箇所を調べなくてはならず、「理論的には可能だが、実際のコードベースのサイズまでスケールさせるのは不可能」と説明されています。
ちなみに「アノテーションを付与」とは以下のことを指します。
const demo = new Demo<string>(); demo.set('hoge'); export { demo };new Demoとなった時点で
const demoの型が確定するので、exportしても上記の問題は発生しません。こうした明示的なアノテーションによって並列処理が可能となり、大幅にパフォーマンスが向上するほか、型を正確に推測するカバレッジが上がることが期待されています。
要するにFlow設計者側の要求ではあるのですが、いずれにせよReactの新機能を使うなどの際にはこれにキャッチアップする必要があります。
Redux, React-Reduxの型アノテーションに対応する
ジェネリックを理解しないままバージョンを上げると真っ先にハマるのはReact, React-Redux周りではないでしょうか。
利用者が多い割に情報が少なく、GithubのIssueを見ても以下のような付け焼き刃の対応が紹介されていたりします。
const container = connect<*, *, *, *, *>( mapStateToProps, mapDispatchToProps )(Component);(*は型推論を強制するものですが、ほとんど型定義を放棄しているので、これを行うのならFlowTypedを置く意義を考え直したほうがよいかもしれません)
React-Reduxの型定義ファイルはかなり力技にも見えますが、しっかりと型情報を失わない形でPropsをコンポーネントのPropsを生成できるように上手く設計されています。
こんな感じの型定義がズラッと並んでいて最初は圧倒されますが、実は一番の近道はこの定義ファイルをしっかりと読み解くことかもしれません。
declare export function connect<-P, -OP, -SP, -DP, S, D>( mapStateToProps: MapStateToProps<S, OP, SP>, mapDispatchToProps: DP, mergeProps: MergeProps<P, OP, SP, $ObjMap<DP, Bind<D>>>, options?: ?Options<S, OP, SP, P>, ): Connector<P, OP, P>;そもそものReact-Reduxの役割を考えればさほど難しくありません。
connectで行っているのは、ReduxのStateからコンポーネントに渡すための情報を抽出する
mapStateToProps、同じくDispatchからコンポーネントへ渡すためのmapDispatchToPropsが主たる要素で、これにOwnPropsを合わせた3つがコンポーネントが受け取るProps型になれば良いのです。例として以下のケースを考えてみましょう。
type StateProps = {| count: number |}; type DispatchProps = {| action: typeof Action |}; type OwnProps = {| children: React.Node |} type Props = {| ...StateProps, ...DispatchProps, ...OwnProps |} const Component = (props: Props) => <Custom {...props} /> const mapStateToProps = (state: State): StateProps => ... const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ... const container = connect<Props, OwnProps, StateProps, DispatchProps, State, Dispatch>( mapStateToProps, mapDispatchToProps )(Component);このようにconnectにアノテーションを付与すると、Flow側でもOwnProps、StateProps、DispatchPropsの3つの型を統合したものがPropsになるかを検証してくれます。
また多くの場合はOwnPropsを利用しませんが、その場合はvoidを指定すれば、StatePropsとDispatchPropsの2つを重ねたらPropsになるかを見てくれます。
つまりそれぞれの型を適切に定義すればFlowが通るようになっているので、エラーを地道に潰していけば自ずと良い感じに型が付いているはずです。
最後に
JavaScriptはエコシステムの進化が早すぎると言われていますが、Flowのこの変更が加わったのは2018年10月のことで、まだまだ網羅的な情報は少ないです。
一方でReact Hooksは良い意味でこれまでのReactの実装を大きく変えるものということで、早い段階でキャッチアップしたいところです。Reduxを入れているとここで紹介したエラーに遭遇する可能性が高いということで、本記事が参考になれば幸いです。
- 投稿日:2019-03-23T05:51:38+09:00
 
登録しているブックマークレット メモ
あんまりないですが、環境移行用にメモ
見ているウェブページのマークダウン形式のリンクを作るjavascript:(function(){const%20e=document.createElement('input');e.value=`[${document.title}](${location.href})`;document.querySelector('body').append(e);e.select();document.execCommand('copy');e.remove();})();選択しているテキストを翻訳する(英→日)javascript:(function(){const%20t=(window.getSelection%20?%20window.getSelection():%20document.getSelection%20?%20document.getSelection():%20document.selection.createRange().text);if(t)open('http://translate.google.com/translate_t?hl=ja&sl=en&tl=ja&q='+encodeURIComponent(t)+'','_blank');})()選択しているテキストを翻訳する(日→英)javascript:(function(){const%20t=(window.getSelection%20?%20window.getSelection():%20document.getSelection%20?%20document.getSelection():%20document.selection.createRange().text);if(t)open('http://translate.google.com/translate_t?hl=ja&sl=ja&tl=en&q='+encodeURIComponent(t)+'','_blank');})()見ているウェブページをツイートするjavascript:(function(){window.open('https://twitter.com/share?url='+encodeURIComponent(window.location.href)+'&text='+encodeURIComponent(document.title),null,'width=500,height=400,toolbar=no,menubar=no,scrollbars=no')})()PictureInPictureで動画を開く(Safari限定)javascript:(function(){document.querySelector('video').webkitSetPresentationMode('picture-in-picture')})()
- 投稿日:2019-03-23T02:14:02+09:00
 
Javascript 画像を動的に切り替える
画像を動的に切り替えたい時がある。
例えばこちらのサイトのように。
https://www.street-academy.com/myclass/14616?sessiondetailid=506634&trigger=browse-history_top
つまり、サムネイル画像?をクリックするとその拡大画像が表示されるというもの参考にした記事はこちらである。
https://www.sejuku.net/blog/63834上記の記事を参考にして
作成したテンプレートはこちら。
基本は一つ目のサイトと同じ機能pic_change.html<html> <body> <img id="mypic" src="pics/1.jpg" width="400" height="300"> <img class = "pic" onclick="slideshow('0')" src="pics/1.jpg" width="10%"> <img class = "pic" onclick="slideshow('1')" src="pics/2.jpg" width="10%"> <img class = "pic" onclick="slideshow('2')" src="pics/3.jpg" width="10%"> <script> var pics_src = new Array("pics/1.jpg","pics/2.jpg","pics/3.jpg"); function slideshow(num){ document.getElementById("mypic").src=pics_src[num]; } </script> </body> </html> <style> body .pic:hover{ opacity: 0.6; filter: brightness(110%);/*リンクにマウスが乗ったら背景色を変更する*/ background-color:brown; } </style>




















