- 投稿日:2020-08-01T21:41:13+09:00
DMMWEBCAMPでの記録(未経験から就職まで)
はじめに
この度DMMWEBCAMPを卒業し、就職を決めることが出来たので学習の記録を書きます。
投稿しようと思ったきっかけ
以下記事を読ませて頂いて
【卒業生】DMMWEBCAMPに通おうか迷っている人に伝えたい事
https://qiita.com/yuki82511988/items/37be28f2486e166fd48f僕もこれからプログラミングをやろうとしている方、学校に通おうと思っている方の役に立てればなという思いから書こうというところに至りました。
僕のこと
軽く自己紹介をします。
現在26歳今年27歳になります。
長野県出身でDMMWEBCAMPに通い転職する目的で引っ越しました。MOSやワープロ検定1級を専門学校の時取得したくらいで、ターミナルやgithubを触ったことはありませんでした。
タイピングがちょっと速くてMicrosoft製品ちょっと使えるぜ!レベルです。
入学する半年くらい前にちょこっと本当に少しProgate(無料版)をやったり、SkillHuckという教材を購入して少しやった程度です。
ちなみにSkillHuckという教材に関しては、僕がその時動画学習が苦手だったのもあり動画を見ているうちに眠くなり2、3章やってやるのを辞めちゃいました。
勿体ないことをしました。
なのでプログラミングのイメージはあるけど種類や何が出来るかは知らないし、文字を出力するのはPタグを使えば良いんでしょ?ぐらいしか知らない状態です。笑高校時代も決して頭が良い訳ではなく、どちらかという必死に悪ぶっている不真面目な方でした。
今ではちょっとした黒歴史です笑
商業高校(偏差値普通よりちょい下ぐらいで留年しかける)→専門学校(誰でも入れる)→医療機器の代理店営業という経歴です。専門学校からは資格取得の勉強を一生懸命やり、クラスで上位の成績の人間にはなれて
大人になってから仕事は一生懸命やっていて、好きで仕事人間になっていましたが、
憧れであったり、物づくりをしてみたい、せっかくの人生だしやってみたいと思うことに挑戦してみたい、という思いからエンジニアを志しました。なぜDMMWEBCAMPにしたのか
色々迷いましたがまず前提として、通学出来るところに焦点を絞って学校選びを始めました。
独学で勉強をやる習慣も無かったですし、多分オンラインだったり無料であればサボるだろうと思っていたからです。
さらに言えば学費もそこそこ無職で引越して一人暮らしとなればお金も当然かかる。
逆にここで投資すればサボろうとか諦めよう逃げようとか思わなくなるなと感じました。選択肢は二つで
・DMMWEBCAMP
・テックキャンプ(確か)転職保証でカリキュラムの内容も似ている中でどういう判断でDMMにしたのかというと
・学習期間が長い(最長4ヶ月)
・4ヶ月コースを受講することでキャッシュバックを受けれる(学費の6、7割)
・4ヶ月コースであればPythonかクラウドを学べる就職支援はどこも凄そうだしな〜って思っていたのでこの3つで選びました。
特に学習期間が長いところに関してはメリットが多いなと思っていたんです。
期間が長ければそれだけサポートを受けながらもいろんな言語を独学で勉強したり、就活時必要になるポートフォリオのレベルとかも上げられると考えていました。
お金が持つだけ学習して、一番良い状態で就活に望みたいというところです。ここから本題に入ります。
DMMWEBCAMPでの学習内容について
学習期間 2020/3月 〜 2020/6月
事前学習
まず事前学習として今後使っていくオンライン教材を1ヶ月前に配布されます。
僕はちょっとしか出来ませんでした。引越しもそうですし、
前職が営業だったので送別会が2日に1回行われていたのです。笑
毎日2日酔いに近い状態です。
しかも独学の習慣もない。
カリキュラムは入学2日前から始めました。。2020/3月(入学)
最初のガイダンスで隣の人のパソコンを覗き見した時に遥かに私より進んでいるのを見て本当に慌てました笑
え、まだ自分HTML2章なのにこの人もうRubyまでやってる、、、、これはやばいと思いここから本気での学習がスタートします。
学ぶ内容はHTML,CSS,GitHub,Ruby,Rails,JavaScript,jQueryでした。
基本的にカリキュラムを自分で進めてわからなければ質問する形式なので、講義もなければ時間の指定もありません。
11時から22時の教室使用時間の中で好きな時間勉強するスタイルです。毎日学校に行って、14時から22時くらいまで休憩を挟みつつ勉強しました。
提出しなければいけない課題が3つあり、2つ目までは期限ギリギリに終わるような実力レベルでしたが、
3つ目に関しては期限よりだいぶ前倒しで終わらせることが出来ました。メンターさんがみんな良い人ですぐに助けてくれたので、自分の力だけで終わらせたとは言い難かったです笑
私には自分で解決する力がその時はまだ無いと認識していたのもあって少し調べてわからなかったらすぐに先輩なり、友達なり、メンターに聞きまくりました。多い時で10回は質問してましたね笑
慣れていないし、全然本質の理解が出来ていないので
エラーが出てエラーを調べても説明している文章の意味がわかんないんです。なのでそこは頼って聞いた方が圧倒的に理解も早く深いですし、全然恥ずかしいことでもなく、成長するのかなと思っています。
まあ、私は元々そんな頭よく無いのでなおさらですね笑
1ヶ月目は後は余った時間を使って、JavaScriptのカリキュラムと
ProgateでRuby on Rails、HTML、CSS、Rubyの復習をして1ヶ月目は終了しました。
カリキュラムを終えた後のProgateは本当におすすめで
Ruby on Railsは特に復習になるので是非有料版に登録してやってみてください。2020/4月 (2ヶ月目)
4/1 ~ 4/10 応用課題
応用課題が10個与えられます。ノルマは特にありません。
僕が終わらせることが出来たのは確か6個で7個目でつまずいたまま時間切れになりました。ここではっきりと理解度や学習の差が出ます。
1ヶ月目に復習とかをあまりせずに良くわからないまま来てしまった方は応用課題をこなせても3つとかになると思います。そして更にここでの遅れというのはそのまま今後に繋がってくるのかなとも感じています。
なので1ヶ月目に曖昧にしてしまったことは調べるなり、
勉強するなり、メンターに聞きまくるなりしてしっかり理解しておかないと本当に周りに差を付けられてしまいます。
オフを取っている時間なんて無いんだと思います。4/11 ~ 4/30 チーム開発
4人1組でECサイトの作成をします。
僕は当時Createアクションが苦手だとはっきり認識していたので、上手いことを言って結構難しめのところに取り組めました。
初めてのチーム開発は楽しかったですし、Gitのブランチの意味もここでちゃんと理解できたりCreataに苦手意識がなくなったりと得るものがめっちゃ多くて成長できました。
周りの人がレベル高めだったのもあって刺激を受けたり、教えてもらったりしながら取り組めました。全体のレベルを拮抗させるようにチームを組んでくださるので、当時真ん中よりちょっと上くらいのレベルにいた僕には自分より出来る人がいるチームはとてもありがたかったです。
さっき書いた1ヶ月目で遅れを取ってしまった方は
基本的にあまり難しい機能の実装を経験できなくなると思います。
当然のことながら期日があるので、チームメンバーも任せてられないという現実があります。
割と忙しいですしね。
会社でも新人だったり、あまり仕事が出来ない人には難しい挑戦をさせないのと同じ感覚ですね。なのでここでも一気にまた実力に開きが出てしまいます。
出来てた人はどんどん出来るようになり、出来なかった人はあまり成長しないまま進むという感じです。もしこれから入学される方は1ヶ月目や事前学習を徹底的に頑張った方が良いと思います。
2020/5月 (3ヶ月目) ポートフォリオ作成
ここでは自分で考えたアイディアを元にしてポートフォリオを作成します。
設計からテスト、デプロイまで1人でやります(メンターには質問出来る)僕はアイディア力に乏しいのもあって、バイクユーザー向けのSNSを作ろうと考えました。
ただSNS機能だけはなく、イベントを主催して人を集めることが出来るような機能も実装しました。ポートフォリオは見たいと言ってくれればGithub含めお見せします。笑
一応機能としては
--SNS--
・ログイン
・画像投稿(配列を用いての複数投稿)
・コメント、いいね(非同期)
・フォロー(非同期)
・DM(非同期)
・コメントやいいね、フォローの通知
・閲覧数の取得
・APIを用いてのコメントの感情分析
・画像表示のスライドショー
・ハッシュタグ検索--イベントーー
・イベント作成
・コメント、参加アクション(非同期)
・開催場所のGoogleMap表示(APIとJavaScriptで)
・参加中や主催したイベントを一目で確認できるカレンダー
・都道府県の表示をするためのgem
--その他--
・項目を選ぶことのできる検索機能
・Rspecテストで380項目
・携帯に対応したレスポンシブ対応
・会員登録しなくても機能の全貌が見えるゲストログイン機能
・https化
・ヘッダーメニューをjsやJqueryでアニメーション付きで実装こんなもんですかね。
確かテーブル数は10ぐらいです。
王道の中では結構頑張ったと思います。笑1ヶ月だけでは全ては実装できず結局次月に実装した機能もあります。
反省点をあげるのであれば、テーマを少し間違えたなと。
やはり就活している人の中にSNSを作る人って凄い多いらしくて、現状差別化が難しいです。
アイディア力が結構勝負でびっくりするような物が作れた方が注目されるのでは?
と感じるのでこれから作る方は
ちょっと工夫してみてください。4ヶ月目 AI学習
正直全然わからないまま終わりました笑
2週間ぐらいでカリキュラムは終了したので、その後は就活に向けて考えがあって
あえてポートフォリオの更新を僕は重ねていました。ポートフォリオの更新を重ねた理由
満足していなかったってのももちろんありましたが、
書類に載る物だったので、他の勉強をするよりここに力を入れる方が企業からの印象がいいんじゃないか?
と思って更新してました。
ポートフォリオに興味を持たれなければ、そもそもGitHubなんて見られないよな。っていう考えです。
レスポンシブ対応だったりRspecテストはこのタイミングでやりました。これがどう就職活動に繋がったのかは後述します。
修了、そして就活へ
まずは担当のキャリアアドバイザーの方と面談します。
私が入社したいと思うような企業の希望を聞いてくださり、
それに沿った形で推薦をしていただくような流れです。この時に書類の添削をするのですが、
ここでは結構修正して頂いてありがたかったです。後は書類選考通過のお知らせを待ちます。
1ヶ月の中で私の書類選考が通った企業は2社でした。
友人の方が多くて若干悲しかったですが、それはしょうがないです。
年齢だったり、経験、ポートフォリオの内容を見て
それを総合的に判断した結果がこれなんだろうなと思いました。
コロナウィルスの影響もあり、なかなか就職が決まらない状況でもありましたから。そこで面接を頂いた1社から内定を頂き、もう1社は最終選考前でしたがお断りし、
今回転職することができました。採用頂いた企業様
面接でポートフォリオを見てくださったことを教えて頂きました。
特にRspecのところに関してはお褒め頂きましたし、スキルも高いと判断してくださったとのことでした。
私も自分の成長に繋がりそうな環境であり、WEB系、自社もSESもやってる、面接官の方に対する印象もとても良かったので内定を承諾しました。
あの時ポートフォリオの更新を重ねたのは間違った選択ではなかったなと感じています。就活に関して思ったこと
自分から就職活動をしなかったので、非常に受け身だったなと反省しています。
このコロナウィルス下での採用状況だったのでもっと自分からも応募をかけた方が良かったなと感じました。もちろん採用頂いた企業様に対しては行きたいと感じて面接を受けたのでありがたいと感じているのですが、
どうしても持っている選択肢が少なくなってしまうと、その中でしか物事を判断出来なくなってしまいます。
本当にここで決めてしまって良いのか。とか、でも就職できなくも困るなとか承諾期間中にあれこれと悩むことになります。なので自分から選択肢を多くする努力をすることで、
自分の市場価値もはっきり見えて、本当に後悔のない転職活動ができるのでは?と思います。就職活動中にやった方が良いと思うこと(主観)
よく面接で他にポートフォリオありますか?
って聞かれます。
面接官によってですが、そのポートフォリオは学校から半強制的に作らされた物であり、
自分の意志で作った物ではないとそう考える方もいらっしゃいます。これは難しいですね本当に笑
自分で作りたいものを作っているのにカリキュラム的に作れと言われたから作ったみたいな笑
なので僕が思うに、別のフレームワークもしくはRailsでもう1つくらいポートフォリオはあった方が、プログラミングに対する姿勢は評価してもらえるのかなと感じています。(なくても学習を続けていれば一応評価はしてもらえますが、こっちの方が多分印象良いです)
僕はJavaなり、SQLなりRubyの復習を7月は行っていたのですが、
そもそもGitHubが見られなければ学習の様子は企業様には伝わらないんですよね。
であれば履歴書にポートフォリオを2つ載せた方が良いんじゃないかと。
それかもしくは一つのポートフォリオのレベルを極限にあげること。
そこまでやってる方って中々いないですから。
結構提出して更新を辞めちゃう人が多い印象です。ただ僕の場合は選考でJavaのテストがあったので学習したことは全然無駄にならなかったんでそこは良かったです。
新しい言語を学ぶ場合はフレームワークまで使ってアプリ作れて初めて高評価に繋がると思うので、僕もどうせならそこまでやれれば良かったなーって今更ながら思います。
それと当たり前ですけど最低でもプログラミングとかその他何かしらの学習はしていないとダメですね。
ただし、勉強する言語にはこだわりすぎないこと。
僕もインフラエンジニアの友人や、IT関係の友人に色々と意見を聞いた上でこう思ったのですが、
よくインフルエンサーと呼ばれる方が言語に関してあれをやった方がいいとか、これはもう時代遅れだとか色々言ってるケースを見ますが、僕らはそもそも実務未経験で、実際の開発現場ですら知らない訳ですよ。
それなのに言語にこだわる理由もこだわれる理由も正直ないと思っていて、
しかもJava、PHPを今独学で勉強していますが、結構似てます。
なのであまりこだわらなくても恐らくどれかの言語の基礎がしっかり出来ているのであれば
実際のエンジニアと言われる方はそこまで苦労せずに新しい言語を取得出来てしまうんじゃないかなって感じました。
繋がる部分も多くて、JavaをやることでRubyを理解したりとかそういうことがよく起きるので、まだ就職していないのであればそんなに勉強する言語自体にはこだわらず、逆に柔軟に勉強をすることで見えてくるものがあると考えています。その中で面白いと思ったものを勤めながらでも独学すればいいんじゃないかなって笑
自分が好きだなっていう風に感じる言語を勉強すればいいよ。って友人もよく言います。なんでもとりあえずやってみようの方が純粋にやってて面白いです。
DMMWEBCAMPに向いていない人
やる気があまりない
人のせいにする
自分の実力を客観的に判断出来ない
わかったふりをするどれかに当てはまる方には本当におすすめしません。
学習もサポートはしてくれますが、基本は自分1人でやっていきますので、わかったふりをしたりやる気があまり出ない人はどんどんと置いてかれます。
メンタルや性格の矯正はさすがにしてくれません笑就活時もメンターがサポートしてくれるのはあくまで書類通過までで、
面接合否は全部自分に対する評価です。
落ちたり就職が決まらないのをメンターのせいにして自分を省みれない人には
本当におすすめできません。
自分の実力がないから書類に通らないし、自分の人間性なり考え方なり伝え方に問題があるから面接に落ちる。っていう風に自分を変えていこうとしない人は多分長い期間就職できないと思います。まとめ
物凄く長くなってしまいました。笑
DMMに入ったことは全然後悔していなくて得たり良かったことが本当にたくさんありました。お互いに研鑽したり応援し合ったり、卒業後も一緒に何か作ろうと言ってくれる友人を得れたこと、
深いレベルで自己分析をする手伝いや学習、就職の支援全般をメンターさんにしてもらえたこと、
プログラミングに関して独学で勉強する習慣がいつの間にかついたこと、
プログラミングを好きなままでカリキュラムを終えさせてくれたこと、
プログラミングが好きになれたこと(毎日やってます)、
何より就職できたことです。現在検討されている方の何かヒントになれれば嬉しいです。
こんな微妙スペックの僕でしたが努力して転職できました!笑本当にありがとうございました。
就職して今まで以上に頑張ります!
- 投稿日:2020-08-01T20:26:32+09:00
[JavaScript]Array.mapとparseIntの組み合わせの落とし穴
どうも、えいやです。
JavaScriptのよくある落とし穴の話をします。
例えば、
'01:24'
のような時刻表示について、時間と分をint
で取ろうと以下のようなコードを書いたとします。fig.1.1'01:24'.split(':').map(parseInt)実はこれは正常に動きません。結果は以下となります。
fig.1.2> '01:24'.split(':').map(parseInt) [ 1, NaN ]試しに
:
区切りとなっている文字列で与えられている数値の数を増やすと、以下のようになります。fig.2% node -v && node v12.16.3 > '01:02:03:04:05:06'.split(':').map(parseInt) [ 1, NaN, 0, 0, 0, 0 ]さて、何が起きているのか正確にわかりますか?
とりあえず意図通りに動かすには、mapが引数として取る関数に引数を与えて、
fig.3> '01:02:03:04:05:06'.split(':').map(n=>parseInt(n)) [ 1, 2, 3, 4, 5, 6 ]とします。
引数を設定するかどうかで動作が変わるので、原因は引数です。
特にScalaなどの他の言語をやっていると見落としがちですが、
Array.map
の引数となる関数が取る引数ですが、実は以下のようになっています。fig.4.1Array.map((currentValue, index, array)=>...);具体的になにが来ているのかは、こうすると分かりやすいです。
fig.4.2> '01:02:03:04:05:06'.split(':').map(console.log) 01 0 [ '01', '02', '03', '04', '05', '06' ] 02 1 [ '01', '02', '03', '04', '05', '06' ] 03 2 [ '01', '02', '03', '04', '05', '06' ] 04 3 [ '01', '02', '03', '04', '05', '06' ] 05 4 [ '01', '02', '03', '04', '05', '06' ] 06 5 [ '01', '02', '03', '04', '05', '06' ]
parseInt
は、第2引数に基数をとりますので、先程の例ではindex
の値が当てられて順に0,1,2,3,4,5
進数として文字列を数値変換していたようですね。それを踏まえて
fig.2
の振る舞いを見てみましょう。引数が0のときはどうやら10進数と解釈されている様子です。で、"1進数"は常にNaN
。その他の進数では、範囲外の数字が使用されている部分を無視して先頭の0
だけを解釈しているようです。JavaScriptを始めとした型の判定が甘い言語では、こうしたうっかりミスを起こしがちなので注意しましょう。
- 投稿日:2020-08-01T20:01:19+09:00
[JavaScript] 関数と変数の宣言と実行
概要
JavaScript で関数の宣言と実行を行う方法と、オブジェクト、引数についての学んだことをまとめる。
前提知識
使用するソフト
Visual Studio Code : js のスクリプト記述のために利用
ターミナル : macOS High Sierra ver 10.13.6 に標準搭載されている実行環境
Google Chrome (Google Chrome 右クリック → [検証] で [Console] 画面を表示)関数
プログラミングでは、処理をまとめて関数として名前をつけることで、呼び出しが可能になる。
関数(ここでは「helloConsole」と命名)を利用して「Hello World」の出力すると、以下のようになる。
.js//関数の定義 function helloConsole(){ console.log("Hello World"); } //関数の実行 helloConsole();関数の定義方法(ここでは、関数名を「hogehoe」とする)
.jsfunction hogehoge(){ //処理内容の記述 }※ 関数の命名規則として、数字・大文字で始めない
アロー関数(矢
=>
を使った関数)function を利用して関数を定義するよりも、シンプルな構文
() => {}
で、こちらが利用されることが多い
アロー関数を利用した「Hello World」の定義.jsconst showMessage = () => { console.log("Hello World"); }アロー関数の定義方法(ここでは、関数名を「hogehoe」とする)
プログラミングにおいて、=
は、右を左に代入という意味.jsconst hogehoge = () => { //処理内容の記述 }オブジェクトの定義
オブジェクトは、以下のように書く
.jsconst user = { name: "太郎", // 文字列 age: 21 // 数字 }ここでは、「user」がオブジェクト名、「name」「age」をプロパティという
オブジェクトを定義すると、各プロパティを取得できます
.jsconsole.log(user.name); console.log(user.age);関数の引数としてオブジェクトを渡す
アロー関数の引数としてオブジェクトを渡すと、一つの変数で複数の値を渡すことができる
.js//オブジェクトの定義 const user2 = { name: "二郎", age: 22 } //取得するプロパティを定義 const logUser = (u) => { console.log(u.name) console.log(u.age) } //関数の実行 logUser(user2);関数とオブジェクトの使用例
「野球少年ランク」を求めるための例文を記載する。
.js//3人の野球少年のスペックをオブジェクトで定義 const baseballBoy1 = { name : "ichiro", power : 90, speed : 80, technique : 100 } const baseballBoy2 = { name : "jiro", power : 30, speed : 50, technique : 80 } const baseballBoy3 = { name : "saburo", power : 10, speed : 10, technique : 10 } //野球少年のランクを求める関数を定義 //野球少年ランクは power と speed と technique の合計値 const baseballBoyLank = (boy) => { const total = boy.power + boy.speed + boy.technique let rank = ""; //合計値に応じたランクの設定 if (total>=250){ rank = "A" } else if (total>=150){ rank = "B"; } else{ rank = "C"; } return rank; } //関数の実行 console.log(getrank(baseballBoy1)); //出力結果:A console.log(getrank(baseballBoy2)); //出力結果:B console.log(getrank(baseballBoy3)); //出力結果:C //getrank によって取得した値を再利用したい場合は、結果を変数に格納する記述方法がいい const baseballboyRank = getrank(baseballBoy1) console.log(baseballboyRank) //出力結果:A const baseballboyRank2 = getrank(baseballBoy2) console.log(baseballboyRank2) //出力結果:B const baseballboyRank3 = getrank(baseballBoy3) console.log(baseballboyRank3) //出力結果:C変数の
let
とconst
の使い分けlet
変数に代入した値の更新が可能
.jslet name = "Ichiro"; console.log(name); //出力結果:Ichiro name = "Jiro"; // 値の更新時には let は不要 console.log(name); //出力結果:Jiroconst
一度定義した値を更新することができない
.jslet name = "Ichiro"; console.log(name); //出力結果:Ichiro name = "Jiro"; console.log(name); //エラーが発生する再代入する場合は let, それ以外の場合は const を利用する
参考ページ
- 投稿日:2020-08-01T19:13:17+09:00
またつまらないLINEbotをつくってしまった。。。
いらっしゃませ。最近LINEbotを作るのにハマっているので、アウトプットします。今回は、入力された文をただオウム返しするだけのつまらないLINEbotを作成します。15分もあれば簡単に作れます。
対象者
- LINEbotを作ってみたい人
- プログラミングなんてしたことない人(今回はGoogleAppScriptで実装を行いますが、下記のソースコードコピペしていただければ動きます)
- LINEする相手が欲しい人
必要なもの
- PC(OSは問いません。)
- LINEアカウント(LINEを使っている人なら多分もっているはずです)
- Googleアカウント
- 人並みはずれた探究心
- オウムへの底しれぬ愛
今回作成するもの
オウム返しLINEbot
友達に紹介して自慢しましょう
作り方
おおまかな流れは以下のようになります。
①LINE developersでチャンネル登録
②GAS(GoogleAppScript)とLINEを連携
③Webhook URLの設定
④完成①LINE developersでチャンネル登録
まずLINEアカウントとgoogleアカウントをお持ちでない方は速攻で作成してください。
続いて以下の手順通りにLINE developersの登録を行っていきます。LINE developersにてログインをクリック
?
LINEアカウントでログインをクリック
(今回は個人の趣味での作成なのでビジネスアカウントでは登録しません)
?
初めての方はメールアドレスかQRコードでのログインを求められます以下のような画面に遷移したらあとはこっちのもんです。僕はいくつかLINEbotを作成しているのでプロバイダーが既にあります。今回は新たに作成ボタンをクリックしてプロバイダーを作成していきます。プロバイダー名は任意です。
新しくプロバイダーが作成されたら、次にMessagingAPIをクリックしてください。
MessagingAPIをクリックすると、実際にLINEで表示されるアイコンやアカウントの名前を設定できる画面に遷移します。ここで注意点があります。アカウント名(正しくはチャンネル名ですがややこしいので)やチャンネル説明は任意で良いのですが、アイコン画像は必ずオウムの画像にしてください。一番こだわってほしいです。
ちなみに僕はこちらのフリー画像を使用させていただいています。
オウムフリー画像ちなみにこのページでメールアドレスの入力が求められますが、LINEアカウントと紐付いているメールアドレスでなくても良いそうです。おしらせがあるときにワンチャンメールが届くくらいです。
規約に同意いただけましたら、作成ボタンをクリックしてください。
最後に、チャンネル作成後のページ内にあるMessagingAPI設定から「応答メッセージ」を無効にしてください。(応答メッセージや挨拶メッセージを無効にした際に無効表示が反映されないことがありますが、安心してください。実機では変更がちゃんと反映されているはずです。)
加えて、チャネルアクセストークンも発行しておいてください。このアクセストークンに指定されたキーを用いて後ほどLINEbotと連携をしていきます。
これにてLINE developoersでのチャンネル作成が完了になります。
②GAS(GoogleAppScript)とLINEを連携
今回用いるGAS(GoogleAppScript)とは非常に優れた言語で、GmailやGoogleカレンダー、Googleマップなどといった、Googleのツールやサービスを連携して開発が行えます。
まずは、googleドライブにアクセスして、左上の新規>その他>GoogleAppScriptを選択してください。
無題のプロジェクトが作成されたら、既にあるコードは全て消して、以下のコードをまるっとコピペしてください。ただし、アクセストークンは先ほどLINE developersで取得したキーに置き換えてください。
//LINE Developersで取得したアクセストークンに置き換えてください var CHANNEL_ACCESS_TOKEN = 'アクセストークン'; function doPost(e) { var json = JSON.parse(e.postData.contents); var replytoken= json.events[0].replyToken; if (typeof replytoken === 'undefined') { return; } //送られてきたメッセージを取得 var user_message = json.events[0].message.text; var url = 'https://api.line.me/v2/bot/message/reply'; //返信用メッセージを作成 UrlFetchApp.fetch(url, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN, }, 'method': 'post', 'payload': JSON.stringify({ 'replyToken': replytoken, 'messages': [{ 'type': 'text', 'text': user_message, }], }), }); return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON); }コードの説明はここではあえて割愛します。
続きまして、左上の 公開>ウェブアプリケーションとして導入をクリックしていただくと以下にあるようなポップアップが表示されると思います。(プロジェクト名は任意です)
このポップアップの一番下の「Who has access ...」を「Anyone, even anonymous」に変更してください。
その後は、deploy→許可を確認→googleアカウントの選択をクリックしていただくと、以下のようなポップアップが出てきます。
こちらは、焦らずに左下の詳細からオウム返しbot(仮)(安全ではないページ)に移動をクリックし、許可を押していただくとURLが発行されますのでそちらをコピーしてください。
③Webhook URLの設定
LINE devlopersのMessaginAPI設定内にあるWebhook URLに先ほどコピーしたURLを貼り付けてください。更新をクリックし、下部にあるWebhookの利用をオンにしてください。最後に検証をクリックし成功と表示されたら優勝です。
④完成
Messaging API設定にあるQRコードかIDから友達追加してみましょう!
成功ですね!
ここまで読んでいただき本当にありがとうございます!
参考記事
PAKUTASO(オウム素材)
Udemy- 【Google Apps Script入門】GASでできることや活用方法まで紹介!最後に
初めてQiitaに投稿してみましたが、アウトプットすると自分の頭の中が整理されますね。
続けていきたいです。
- 投稿日:2020-08-01T19:00:01+09:00
Vue.jsのドキュメントをまとめてみた
Vue.jsとは?
フロントエンドのフレームワーク。
'はじめに'の部分を自分なりに噛み砕いてみた特徴
コンポーネントの概念
vue.jsでは画面部品単位でvueインスタンスを作成し、それらを組み合わせることでページを組み立てていく。
コンポーネントシステムは Vue.js におけるもうひとつの重要な抽象概念です。「小さく、自己完結的で、(多くの場合)再利用可能なコンポーネント」を組み合わせることで、大規模アプリケーションを構築することが可能になります。アプリケーションのインターフェイスについて考えてみると、ほぼすべてのタイプのインターフェイスはコンポーネントツリーとして抽象化することができます:
(引用:https://jp.vuejs.org/v2/guide/index.html)この小さな例で説明していきます
<div id="app-7">
の中に<todo-item>
というタグがあるのがわかると思います。これがコンポーネントというもので<コンポーネント名>
タグとしてtemplate内に「部品」を埋め込む事ができます。子コンポーネントへの値渡し
v-bindを用いてtodoプロパティへ変数を渡しています。
宣言的レンダリング
vueのコアでは、template構文という文法でコンパクトにhtmlに変数を描画できる。
変数の描画
template内{{}}にdataで定義した変数を埋め込める
index.html<div id="app"> {{ message }} </div> <script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script>リアクティブ
data:内の変数が更新されるとテンプレートがそれに「反応」して更新が反映される。
テンプレート構文内のバスケット{{}}内の変数名とVueインスタンスのdataプロパティに格納されている変数がリンクしている。ディレクティブ
Vue.jsで用意されたhtmlタグの属性のこと。
(例)v-bindディレクティブ
属性のvalueをバインドできる(下記の例はtitle属性をバインドしている)index.html<div id="app-2"> <span v-bind:title="message"> Hover your mouse over me for a few seconds to see my dynamically bound title! </span> </div> <script> ar app2 = new Vue({ el: "#app-2", data: { message: "You loaded this page on " + new Date().toLocaleString() } }); </script>参考
- 投稿日:2020-08-01T18:20:52+09:00
javascriptを使って簡単な計算機を作るpart.last 入門者向け
計算機を作る
完成物
See the Pen jOWgaGJ by ライム (@raimumk2) on CodePen.
サンプルコード
HTML
caluculate.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="css/caluculate.css"> <title>計算機</title> </head> <body> <div class="caluculate"> <div class="cal-body"> <div class="wrapper"> <div id="number-text">0</div> </div> <div class="other-btns"> <button id="clear-btn">CLEAR</button> <button id="record-btn">RECORD</button> </div> <div id="btns"> <div id="num-btns"> <button onclick="number(7)">7</button> <button onclick="number(8)">8</button> <button onclick="number(9)">9</button> <button onclick="number(4)">4</button> <button onclick="number(5)">5</button> <button onclick="number(6)">6</button> <button onclick="number(1)">1</button> <button onclick="number(2)">2</button> <button onclick="number(3)">3</button> <button id="zero" onclick="zero(0)">0</button> <button name="point" onclick="point('.')">.</button> <button id="equal" onclick="calc('=')">=</button> </div> <div id="symbol-btns"> <button class="symbol-btn" onclick="calc('/')">/</button> <button class="symbol-btn" onclick="calc('*')">*</button> <button class="symbol-btn" onclick="calc('-')">-</button> <button class="symbol-btn" onclick="calc('+')">+</button> </div> </div> </div> <div class="cal-lists"> <div class="lists-name">-MEMO-</div> <div class="lists-btn"> <button id="clear-all">Clear All</button> </div> <ul id="result-lists"></ul> </div> </div> <script src="js/caluculate.js"></script> </body> </html>
CSS
caluculate.css* { margin: 0; padding: 0; } .caluculate { margin: 100px auto; display: table; border-spacing: 5px 0; } .cal-body { display: table-cell; background-color: #6289a4; padding: 30px 15px; border-radius: 5px; } .wrapper { width: 300px; margin: 0 auto; } .wrapper > #number-text { background-color: #fff; width: 285px; height: 54px; line-height: 54px; margin-left: 5px; margin-bottom: 15px; font-size: 48px; border: 1px solid black; /* 右から左へ入力するためのスタイル */ text-align: right; } .other-btns { margin: 0 auto; width: 300px; } #clear-btn { width: 135px; margin-left: 5px; font-size: 24px; color: #fff; background-color: #8aa3b9; /* 上下のズレを直すためのスタイル */ vertical-align: middle; } #record-btn { width: 135px; font-size: 24px; margin-left: 13px; color: #fff56c; background-color: #8aa3b9; /* 上下のズレを直すためのスタイル */ vertical-align: middle; } #btns { width: 300px; display: flex; margin: auto; } button { width: 65px; height: 57px; } #num-btns { margin: 5px; } #num-btns > button { margin-bottom: 5px; font-size: 24px; color: #fff; background-color: #8aa3b9; } #symbol-btns { height: 228px; display: flex; flex-direction: column; display: inline-block; margin-top: 5px; } #symbol-btns > .symbol-btn { margin-bottom: 5px; height: 57px; font-size: 24px; text-align: center; background-color: #f68b58; } #symbol-btns > .active { background-color: #fecf8d; } /* 計算結果リスト */ .cal-lists { display: table-cell; vertical-align: top; width: 200px; background-color: #fff8dc; overflow-y: scroll; } .lists-name { text-align: center; color: #f37053; } .lists-btn{ text-align: left; margin-bottom: 5px; } #clear-all { height: 24px; width: 64px; margin-left: 5px; background-color: #f37053; border: 1px solid; border-radius: 5px; /* position: fixed; */ } ul { margin: 0 auto; height: 400px; } #result-lists > li { font-size: 20px; list-style: none; text-align: right; color: #333; } #formula { background-color: #fff799; } #answer { background-color: #fecf8d; font-weight: bold; }
JavaScript
caluculate.js//計算用 var show = document.getElementById('number-text'); var total = ''; //合計 var operator = ''; //演算子 var currentValue = ''; //現在の値 var flag = 0; //ボタンが押されたあとに効かなくする※flag(フラグ)を立てる。最初は0を代入。 // 計算結果リスト用 var formula1 = 0; var formula2 = 0; //数字入力の関数 var number = data => { //押されたボタンの値 data()をアロー関数にしている if (currentValue === '0') { return; //「0.」と入力しなければ数字を打てなくする } else if (currentValue.length <= 8) { flag = 0; currentValue += data; show.textContent = currentValue; // console.log(show.textContent); //確認用 } }; //0についての関数 var zero = data => { if(currentValue === '0') { return; //最初の文字が0のとき0を押せなくする } else if (currentValue.length <= 8){ flag = 0; currentValue += data; show.textContent = currentValue; // console.log(show.textContent); } } //小数点(.)の関数 var point = data => { if (currentValue === '') { return; //最初に小数点を押せなくする } else if (!currentValue.includes('.')) { currentValue += data; show.textContent = currentValue; } } //計算の関数 var calc = data => { if (flag === 0 && data !== "=") { flag = 1; var formula = total + operator + currentValue; total = eval(formula); operator = data; formula1 = currentValue; //計算結果リスト用 currentValue = ''; show.textContent = total; console.log(operator); //確認用 } else if (flag === 1 && data === "=") { var formula = total + operator + total; total = limitNum(eval(formula)); console.log(formula); formula2 = currentValue; //計算結果リスト用 currentValue = ""; show.textContent = total; } else if (data === "=") { flag = 1; var formula = total + operator + currentValue; total = limitNum(eval(formula)); console.log(formula); formula2 = currentValue; //計算結果リスト用 currentValue = ""; show.textContent = total; } else { operator = data; //演算子入力を変更できる console.log(operator); } }; //ボタン切り替え機能の関数 var btns = document.getElementsByClassName('symbol-btn'); for (var i = btns.length - 1; i >= 0; i--) { btnAction(btns[i],i); } function btnAction(btnDOM, btnId) { btnDOM.addEventListener('click', function() { this.classList.add('active'); for(let i = btns.length - 1; i >= 0; i--) { if(btnId !== i) { if(btns[i].classList.contains('active')) { btns[i].classList.remove('active'); } } } }); } //小数点以下の桁数を揃える関数 function limitNum(num) { return Math.round(num*10000000)/10000000; } // RECORDボタンの関数 //計算結果を表示 function resultAddAnswer() { const li = document.createElement('li'); li.id = 'answer'; const answer = show.textContent; const lists = document.createTextNode(answer); li.appendChild(lists); const result = document.getElementById('result-lists'); result.appendChild(li); }; //計算式を表示 function resultAddFormula() { const li = document.createElement('li'); li.id = 'formula'; const formula = formula1 + operator + formula2; const lists = document.createTextNode(formula); li.appendChild(lists); const result = document.getElementById('result-lists'); result.appendChild(li); } var record = document.getElementById('record-btn'); record.addEventListener('click', () => { if (operator != false) { //演算子ボタンが押された時にだけ、計算式を結果を出すようにしている resultAddFormula(); formula1 = total; //計算結果を使って続けて計算した場合に、前の計算結果をformula1として反映させるため } resultAddAnswer(); }); //CLEARボタンの関数 function reset() { operator = ''; total = ''; currentValue = ''; flag = 0; show.textContent = '0'; }; function resetBackColor() { [].forEach.call(btns, function(e) { e.classList.remove('active'); }); } var clear = document.getElementById('clear-btn'); clear.addEventListener('click', () => { reset(); resetBackColor(); }); //計算結果リストの削除ボタンの関数 var allClear = document.getElementById('clear-all'); allClear.addEventListener('click', allClearBtn); function allClearBtn() { const result = document.getElementById('result-lists'); while(result.lastChild) { result.removeChild(result.lastChild); } }今回作る機能
計算結果をリストに追加する機能
目次
1.計算結果をリストに追加する。
2.計算結果を出す過程の計算式もリストに追加する。
(今後の構想にはなかったが、突如作ることを決めた)3.「1.」と「2.」の関数をRECORDボタンを押した時に呼び出す
4.不具合の修正
5.計算結果リストの編集ができる機能
削除ボタンのみ6.スタイルの変更
計算機の見た目や計算結果リストの見た目7.参考サイト
8.感想
1.計算結果をリストに追加する。
該当するコード
caluculate.js//計算結果をリストに追加する function resultAddAnswer() { const li = document.createElement('li'); li.id = 'answer'; const answer = show.textContent; const lists = document.createTextNode(answer); li.appendChild(lists); const result = document.getElementById('result-lists'); result.appendChild(li); };3行目.
const li = document.createElement('li');
liという変数に、li要素を生成するオブジェクトを入れる。5行目.
const answer = show.textContent;
answerという変数に、計算結果の内容を入れる。6行目.
const lists = document.createTextNode(answer);
listsという変数に、変数answerの内容でTextノードを生成するオブジェクトを入れる。8行目.
li.appendChild(lists);
変数listsの生成したTextノードを、li要素としてDOMツリーに挿入する。10行目.
const result = document.getElementById('result-lists');
resultという変数に、ID名(result-lists)がついた要素を取得。11行目.
result.appendChild(li);
変数resultで取得した要素の最後に、li要素を子ノードとして追加する。2.計算結果を出す過程の計算式もリストに追加する。
該当するコード
caluculate.jsvar formula1 = 0; //1つ目の数値を保持するための関数 var formula2 = 0; //2つ目の数値を保持するための関数 //計算を行う関数 var calc = data = > { if (flag === 0 && data !== '=') { formula1 = currentValue; //演算子ボタン押すまでに入力した数値をformula1に保持 } else if (flag === 1 && data === '=') { formula2 = currentValue; //=ボタンを押すまでに入力した数値をformula2に保持 } else if (data === '=') { formula2 = currentValue; //上記と同様。 } }caluculate.js//計算式をリストに追加する function resultAddFormula() { const li = document.createElement('li'); li.id = 'formula'; const formula = formula1 + operator + formula2; const lists = document.createTextNode(formula); li.appendChild(lists); const result = document.getElementById('result-lists'); result.appendChild(li);6行目.
const formula = formula1 + operator + formula2;
計算結果を求めるために入力した値を、変数formulaに入れる。7行目.
const lists = document.createTextNode(formula);
listsという変数に、変数formulaの内容でTextノードを生成するオブジェクトを入れる。3.「1.」と「2.」の関数をRECORDボタンを押した時に呼び出す
該当するコード
caluculate.jsvar record = document.getElementById('record-btn'); record.addEventListener('click', () => { resultAddFormula(); resultAddAnswer(); });ID名:record-btnがついた要素をクリックした時に、計算式と計算結果をリストに追加する。
4.不具合の修正
1.計算式をリストに追加する際の不具合
計算式と計算結果をリストに追加することができたが、
計算結果をそのまま次の計算に使う場合に起きた。
例:「1+1=2」→「2+1=3」という計算の場合、
計算結果リストでは、
1+1
2
1+1 ←この部分がおかしい
3と表示された。
これは
const formula = formula1 + operator + formula2
のformula1が前回の計算から変わってないから、このように表示されてしまっているからだと推測した。最初は、計算を行う関数や数字入力の関数にいろいろ試していたが、
最終的には
record.addEventListener
に、caluculate.jsvar record = document.getElementById('record-btn'); record.addEventListener('click', () => { if (operator != false) { //演算子ボタンが押された時にだけ、計算式を結果を出すようにしている resultAddFormula(); formula1 = total; //計算結果を使って続けて計算した時、前の計算結果をformula1として扱う } resultAddAnswer(); });と加えてみたところ、この問題は自己解決することができた。
2.「01」と入力できてしまう
caluculate.js//数字入力の関数 var number = data => { //押されたボタンの値 data()をアロー関数にしている if (currentValue === '0') { return; //「0.」と入力しなければ数字を打てなくする } else if (currentValue.length <= 8) { flag = 0; currentValue += data; show.textContent = currentValue; console.log(show.textContent); //確認用 } };これは、数字入力の関数に
if (currentValue === '0') { return;}
を追加するだけで解決。5.計算結果リストの編集ができる機能
該当するコード
caluculate.js//計算結果リストのボタンの関数 var allClear = document.getElementById('clear-all'); allClear.addEventListener('click', allClearBtn); function allClearBtn() { const result = document.getElementById('result-lists'); while(result.lastChild) { result.removeChild(result.lastChild); } }
removeChild()
は、子要素を一つだけしか削除ができないので、
対象の子要素がなくなるまでループ処理するように記述する必要があった。6.スタイルの変更
該当するコード
caluculate.js//計算式と計算結果を区別するためのコード function resultAddAnswer() { li.id = 'answer'; }; function resultAddFormula() { li.id = 'formula'; };実際にあるような計算機の見た目と、見やすい計算結果リストの見た目になるようスタイルを変更した。
スクリーンショット
リストに追加機能を使うと...
7.参考サイト
CSSに関する
qiita:よく使うCSSで要素を横並びにする方法と使い分け
【CSS】display:table-cellにmarginを指定して間隔を作りたい時は
HTMLでスクロールバーを表示・非表示する方法を現役エンジニアが解説【初心者向け】
JSに関する
document.createElement - 指定タグでのエレメント作成
JavaScriptやjQueryでの変数が「空かどうか」のチェック方法
リスト編集機能に関する
qiita:【DOM基礎】要素内容の取得・設定/ノードの作成・挿入・削除
qiita:[JavaScript]複数の子要素を削除する。
【JavaScript】特定の子要素(子ノード)を削除する【removeChild】
8.感想
この計算機作り自体、最初はインプットした内容をちょっと試しにアウトプットしてみるか程度の思いで取り組んでいたのだが、
思いの外、熱中してしまい、作っているうちにいろいろなアイデアが思い浮び、そのアイデアを実際に実現できたときにはとても楽しかった。
ほとんどはインターネット上の情報通りに実装していたが、調べた内容についてまた調べるとやっていたので、かなり時間を掛けていたと自覚しているが、調べることで問題解決に繋がっていたので調べる癖は大事。
一通りインプットが済んだ後に行うアウトプットはとても有意義だと実感したし、これからも積極的に取り組んで行こうと決めました。
後、アウトプットした内容をこうやってqiitaのような投稿サイト(人目に触れるようなサイト)で、記事にするのも「しっかりと書こう」という気になって中途半端になりづらいし、こちらも続けて行こうと思いました。
- 投稿日:2020-08-01T17:19:19+09:00
P5.js 日本語リファレンス(DEGREESなど)
このページでは「P5.js 日本語リファレンス」 の 関数を説明します。
※このページでは DEGREES、RADIANS、HALF_PI、PI、QUARTER_PI、TAU、TWO_PI の説明を記載しています。
DEGREES
説明文
angleMode() で使用する定数で、DEGREEDS を指定すると角度は 例えば円は0°〜360°で扱います。
構文
angleMode(DEGREES)
RADIANS
説明文
angleMode() で使用する定数で、RADIANS を指定すると角度は 例えば円は 0.0 〜 2π (6.28318531)で扱います。
構文
angleMode(RADIANS)
HALF_PI
説明文
HALF_PIは 1.57079632679489661923の値(πの半分)を持つ数学定数です。これは円の円周と直径の比率の半分です。三角関数sin() およびcos() と組み合わせると便利です。
構文
sin(HALF_PI)
cos(HALF_PI)
PI
説明文
PIは 3.14159265358979323846の値(π)を持つ数学定数です。 これは円の円周と直径の比です。 三角関数sin() およびcos() と組み合わせると便利です。
構文
sin(PI)
cos(PI)
QUARTER_PI
説明文
QUARTER_PIは 0.7853982の値を持つ数学定数です。これは,円の円周と直径の比率の4分の1です。三角関数sin() およびcos() と組み合わせると便利です。
構文
sin(QUARTER_PI)
cos(QUARTER_PI)
TAU
説明文
TAUは 6.28318530717958647693の値(2π)を持つ数学定数TWO_PIのエイリアスです。 これは, 円の円周と直径の比の2倍です。 三角関数sin() およびcos() と組み合わせると便利です。
構文
sin(TAU)
cos(TAU)
TWO_PI
説明文
TWO_PIは 6.28318530717958647693の値を持つ数学定数です。 これは,円の円周と直径の比の2倍です。 三角関数sin() およびcos() と組み合わせると便利です。
構文
sin(TWO_PI)
cos(TWO_PI)
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:06:26+09:00
P5.js 日本語リファレンス(circle)
このページでは「P5.js 日本語リファレンス」 の circle関数を説明します。
circle()
説明文
画面に円を描きます。円は単純な閉じた形状です。これは, 指定されたポイントつまり中心から指定された距離にある平面内のすべてのポイントのセットです。この関数は ellipse() の特別なケースで楕円の幅と高さが同じです。楕円の高さと幅は円の直径に対応します。デフォルトでは最初の2つのパラメータは円の中心の位置を設定し、3番目のパラメータは円の直径を設定します。
構文
circle(x, y, d)
パラメタ
x
Number:円の中心のx座標y
Number:円の中心のy座標d
Number:円の直径例1
function setup() { createCanvas(200, 200); //中心点(100, 100)に直径150の円を描画します。 circle(100, 100, 150); }実行結果
https://editor.p5js.org/bit0101/sketches/375ggSYCx
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:06:14+09:00
P5.js 日本語リファレンス(ellipse)
このページでは「P5.js 日本語リファレンス」 の ellipse関数を説明します。
ellipse()
説明文
画面に楕円を描画します。幅と高さが等しい楕円は円です。最初の2つのパラメータは中心点を設定し、3番目と4番目のパラメータは楕円の幅と高さを設定します。高さが指定されていない場合、幅の値は幅と高さの両方に使用されます。負の高さまたは幅が指定されている場合は、絶対値が使用されます。原点は ellipseMode() で変更できます。
構文
ellipse(x, y, w, [h])
ellipse(x, y, w, h, detail)
パラメタ
x
Number:楕円のx座標y
Number:楕円のy座標w
Number:楕円の幅h
Number:楕円の高さ (オプション)detail
Number:楕円を描画する頂点数(WebGLモードの場合)例1
function setup() { createCanvas(200, 200, WEBGL); //中心点(0, 0)に幅105、高さ55、頂点数10の円を描画します。 ellipse(0, 0, 105, 55, 10); }実行結果
https://editor.p5js.org/bit0101/sketches/n6XO9PXGU
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:05:56+09:00
P5.js 日本語リファレンス(line)
このページでは「P5.js 日本語リファレンス」 の line関数を説明します。
line()
説明文
画面に線(2点間の直接パス)を描画します。 4つのパラメータを持つline() は 2D で、6つのパラメータを持つline() は 3D で線を描画します。線に色を付けるには stroke() を使用します。線を塗りつぶすことはできないため fill() は線の色に影響を与えません。 2D の line はデフォルトで1ピクセルの幅で描画されますが、これは strokeWeight() で変更できます。
構文
line(x1, y1, x2, y2)
line(x1, y1, z1, x2, y2, z2)
パラメタ
x1
Number:最初の点のx座標y1
Number:最初の点のy座標x2
Number:2番目の点のx座標y2
Number:2番目の点のy座標z1
Number:最初の点のZ座標z2
Number:2番目の点のZ座標例1
function setup() { createCanvas(400, 400); // 始点(30, 20) から 終点(85, 75)にラインを描画 line(30, 20, 85, 75); // 色を赤色にする stroke("#FF0000"); // 線幅を3にする strokeWeight(3) line(85, 20, 85, 75); }実行結果
https://editor.p5js.org/bit0101/sketches/P8Q1Imn_6
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:05:40+09:00
P5.js 日本語リファレンス(point)
このページでは「P5.js 日本語リファレンス」 の point関数を説明します。
point()
説明文
点を描画します。最初のパラメータはポイントの水平方向の値、2番目のパラメータはポイントの垂直方向の値です。ポイントの色は stroke() で変更されます。ポイントのサイズは strokeWeight() で変更されます。
構文
point(x, y, [z])
point(coordinate_vector)
パラメタ
x
Number:X座標y
Number:Y座標z
Number:z座標(WebGLモードの場合)(オプション)coordinate_vector
p5.Vector:座標ベクトル例1
function setup() { createCanvas(400, 400); //ポイントのサイズを10ピクセルにします strokeWeight(10); //色を紫色にします stroke('purple'); point(30, 20); point(85, 20); point(85, 75); point(30, 75); //色を青色にします stroke('blue'); // 座標ベクトルを設定して点を描画 let a = createVector(10, 10); point(a); //色を赤色にします stroke('red'); // 座標ベクトルで点の位置を指定 point(createVector(20, 20)); }実行結果
https://editor.p5js.org/bit0101/sketches/MROsg4TBi
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
P5.js 日本語リファレンス
- 投稿日:2020-08-01T17:05:26+09:00
P5.js 日本語リファレンス(quad)
このページでは「P5.js 日本語リファレンス」 の quad関数を説明します。
quad()
説明文
四角形を描画します。四角形は四辺形のポリゴンです。長方形に似ていますがエッジ間の角度は90度に制限されていません。最初のパラメータのペア (x1, y1) は最初の頂点を設定し、後続のペアは定義された形状を中心に時計回りまたは反時計回りに進む必要があります。 z引数は、WEBGLモードのみ機能します。
構文
quad(x1, y1, x2, y2, x3, y3, x4, y4)
quad(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4)
パラメタ
x1
Number:最初の点のx座標y1
Number:最初の点のy座標x2
Number:2番目の点のx座標y2
Number:2番目の点のy座標x3
Number:3番目の点のx座標y3
Num ber:3番目の点のy座標x4
Number:4番目の点のx座標y4
Number:4番目の点のy座標z1
Number:最初の点のZ座標z2
Number:2番目の点のZ座標z3
Number:3番目の点のZ座標z4
Number:4番目の点のz座標著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:05:12+09:00
P5.js 日本語リファレンス(rect)
このページでは「P5.js 日本語リファレンス」 の rect関数を説明します。
rect()
説明文
画面に長方形を描画します。長方形はすべての角度が90度の4辺の形状です。デフォルトでは最初の2つのパラメータは左上隅の位置を設定し3番目のパラメータは幅を設定し4番目のパラメータは高さを設定します。ただし、これらのパラメータの解釈方法は rectMode() で変更できます。
5番目、6番目、7番目、8番目のパラメータが指定されている場合、それぞれ左上隅、右上隅、右下隅、左下隅の隅の半径を決定します。半径を省略した場合、以前に指定した半径値の値に設定されます。
構文
rect(x, y, w, [h], [tl], [tr], [br], [bl])
rect(x, y, w, h, [detailX], [detailY])
パラメタ
x
Number:長方形のx座標y
Number:長方形のy座標w
Number:長方形の幅h
Number:長方形の高さ (オプション)tl
Number:左上隅のオプションの半径 (オプション)tr
Number:右上隅のオプションの半径 (オプション)br
Number:右下隅のオプションの半径 (オプション)bl
Number:左下隅のオプションの半径 (オプション)detailX
Number:x方向のセグメント数(WebGLモードの場合)(オプション)detailY
Number:y方向のセグメント数(WebGLモードの場合)(オプション)例1
function setup() { createCanvas(400, 400); stroke("red"); //左上点(30, 20)に幅55と高さ80の長方形を描画します。 rect(30, 20, 55, 80); stroke("blue"); //角が丸く, 半径が15の長方形を描画します。 rect(110, 20, 55, 55, 15); stroke("green"); //以下の半径の角が丸い長方形を描画します: //左上= 20, 右上= 15, 右下= 10, 左下= 5。 rect(190, 20, 55, 55, 20, 15, 10, 5); }実行結果
https://editor.p5js.org/bit0101/sketches/gbKYl62iq
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:04:52+09:00
P5.js 日本語リファレンス(square)
このページでは「P5.js 日本語リファレンス」 の square関数を説明します。
square()
説明文
画面に正方形を描画します。正方形はすべての角度が90度の4辺の形状で,辺の長さは同じです。この関数は幅と高さが同じである rect() の特殊なケースであり、パラメータはサイドサイズの "s" と呼ばれます。デフォルトでは、最初の2つのパラメータは左上隅の位置を設定し、3番目のパラメータは正方形の辺の長さを設定します。ただし、これらパラメータの解釈方法は rectMode() で変更できます。
4番目、5番目、6番目、7番目のパラメータが指定されている場合は、それぞれ左上隅、右上隅、右下隅、左下隅の半径を設定します。省略したときの半径は以前に指定した半径の値に設定されます。
構文
square(x, y, s, [tl], [tr], [br], [bl])
パラメタ
x
Number:正方形のx座標y
Number:正方形のy座標s
Number:正方形の辺のサイズtl
Number:左上隅の半径 (オプション)tr
Number:右上隅の半径 (オプション)br
Number:右下隅の半径 (オプション)bl
Number:左下隅の半径 (オプション)例1
function setup() { createCanvas(400, 400); stroke("green"); //場所(30, 20)に, 辺の長さが55の正方形を描画します。 square(30, 20, 55); stroke("blue"); //角が丸く, 半径が20の正方形を描画します。 square(110, 20, 55, 20); stroke("red"); //角が丸く, 次の半径の正方形を描きます: //左上= 20, 右上= 15, 右下= 10, 左下= 5。 square(190, 20, 55, 20, 15, 10, 5); }実行結果
https://editor.p5js.org/bit0101/sketches/Br0Oyq8JH
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T17:04:26+09:00
P5.js 日本語リファレンス(triangle)
このページでは「P5.js 日本語リファレンス」 の triangle関数を説明します。
triangle()
説明文
三角形は3つの点を結んで作成される平面です。最初の2つの引数は最初の点を設定し、2番目、3番目の引数は2番目の点を設定し, 最後の2つの引数は3番目の点を設定します。
構文
triangle(x1, y1, x2, y2, x3, y3)
パラメタ
x1
Number:最初の点のx座標y1
Number:最初の点のy座標x2
Number:2番目の点のx座標y2
Number:2番目の点のy座標x3
Number:3番目の点のx座標y3
Number:3番目の点のy座標著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T16:41:02+09:00
DDD特別夏季講習 / 3時限目 : レポジトリ
はじめに
本記事は前回の記事の続きになります。DDDをゼロから学びたい方はまず1時限目からの受講をお勧めします。
これまでの授業:
DDD特別夏季講習 / 1時限目:値オブジェクトとエンティティ
DDD特別夏季講習 / 2時限目:ドメインサービス今日は、レポジトリについてまとめていきたいと思います。
対象読者
- 職場でドメイン駆動開発を使って開発を行っている方
- これからドメイン駆動開発の導入を検討している方
- エリック・エバンスの本分厚いよー、ぴえん?って方
- その他、ドメイン駆動開発ってなにー??って方
レポジトリの意義・必要性
前回までの記事で、ドメインモデルをドメインオブジェクトの実装に落とし込むための手法について解説してきました。
では前回までの内容を踏まえて、実際にドメインを実装してみましょう。class User { const buy = (item: Item[]) => { const connectionString = // DBと接続するための処理... { DB.hogehoge... // DBのCRUD処理 } } }まあ実際の処理はめんどくさいので割愛しますが、たいていの場合、ドメインにはそのドメインの振る舞いが定義され(userが何か商品を買うとか、プロフィールを変更するとか)、そしてそのほとんどがDBに値を書き込んだり、DBの値を参照します。
ということはこのまま実装を進めていくと(進めていけばいくほど)、ドメインにDB処理のコードが入り込むことになります。
前回の授業までで、ドメインは現実世界のドメインを実装に落とし込んだもので、いわばコードで表現されたドキュメントのようなものだと解説しました。DB処理が大量に入り込んだコードでは、そのドメインがどう言ったものかよくコードの細部まで読み込まなければわかりにくくなってしまいます。
この問題を解決するのがレポジトリです。レポジトリの責務
レポジトリの責務はDB処理です。受け取ったデータをDBに永続化したり、DB内のデータを参照しなんらかの値を返したりする処理が記述されます。
DB処理を、このレポジトリ層にうつし、ドメイン層ではそれを呼び出すだけという風にすれば、ドメイン層は大変すっきりし、ドキュメント性も向上します。// ドメイン層 class User { const buy = (item: Item[]) => { userRepository.save(item) // ドメイン層にはDB処理のコードは書かず、レポジトリ層で実装したそれを呼ぶ } } // レポジトリ層 class UserRepository { const save // DB接続、CRUD処理の記述 }はい、これで一件落着!簡単じゃーん。と思ったそこのあなた。本当にそうでしょうか??
これはDDD的に(もっというとアーキテクチャ的に)、御法度です。依存関係
ここで一つ理解しておくべき概念があります。それが依存関係という考え方です。
以下に例をあげます。class Human extends Animal { const think = () => ... bark("pien") } class Animal { const bark = (cry: string) => ... }このケースではHumanクラスがAnimalクラスを継承しています。Animalクラスは吠えるみたいなbarkメソッドを持っています。これは基本的にどの動物も泣き声を持っているからですね。これによって、Humanクラスではいちいちbarkメソッドを定義しなくてもbarkメソッドを使えます。
逆に言えばHumanクラスでbarkメソッドを実行するにはAnimalクラスの存在が必須です。これは、HumanクラスがAnimalクラスに依存しているからに他なりません。DDDにおけるレイヤー間の依存関係
この依存関係はDDDのレイヤー間でも生じます。そしてそのあるべき関係性は決まっています。
これは採用するアーキテクチャにもよりますが、大枠は変わりません。外側の層から内側の層のみへの依存が認められ、その逆は認められません。ですが先ほどあげた例ではドメイン層が一番外側にあるレポジトリ層(インフラ層)に依存しています。// ドメイン層 class User { const buy = (item: Item[]) => { userRepository.save(item) // ドメイン層にはDB処理のコードは書かず、レポジトリ層で実装したそれを呼ぶ } } // レポジトリ層 class UserRepository { const save // DB接続、CRUD処理の記述 }これを解決するために、抽象に依存させることによる依存性の逆転を用います。
抽象に依存せよ
では、依存関係が望ましいものになるように先ほどのコードをリファクタしましょう。
まずはレポジトリを実装クラスと型クラスに分けます// 型クラス class UserRepository { const save(item: Item[]): Item[] } // 実装クラス class UserRepositoryImpl extends UserRepository { const save = (item: Item[]) => { // DBのCRUD処理 } }そして型クラスであるUserRepositoryクラスはドメイン層(場合によってはユースケース層におくこともあるが)に置きます。そして実装クラスはレポジトリ層に置きます。
これによって依存性は
ドメイン -> レポジトリ
から、
ドメイン <- レポジトリに逆転します。
実装クラスはより抽象度の高い型クラスに依存するためです。これにより依存性の原則は守られます。
なぜ依存関係が大切か
アプリケーションサービスは変化するものです。ユーザからの要望や事業の方向性の転換によって、改修に次ぐ改修が生じます。開発者は今動くものを作るだけでなく、将来の改修リスクについて常に考える必要があります。
DDD及びそれに伴うアーキテクチャの原則を守ることは、そのリスクへの処方箋です。
ドメインはサービスの核となる概念です。これが頻繁に変更されることはありません。
ところがより外側の層であるレポジトリ層はどうでしょう。新機能の追加や、既存機能の修正に影響を受けやすいと言えます。また、DBの変更など、技術的な要因によって変更があるかもしれません。
依存関係がしっかりと守られていれば、コードの変更箇所を最小限に抑えることができます。終わりに
いかがだったでしょうか?今日の授業ではレポジトリについて解説しました。レポジトリによってドメインのドキュメント性が高まることに加えて、正しく依存性を守りつつ実装すれば、将来の改修リスクに備えることができます。
次回はコントローラ層について学びます。是非お楽しみに。
- 投稿日:2020-08-01T15:55:22+09:00
bxsliderでリンクが効かなくなった時の対処法
jQueryプラグイン「bxslider」でリンクが効かなくなるという現象に遭遇したので対処法を探してみました。
すでにいくつか対応されている記事を拝見しましたが、スマートフォンとタブレットではスワイプ機能は使えるように調整をしてみました。原因
Chromeの仕様変更により、スライダーのスワイプやドラッグ操作でスライドを切り替える機能が原因のようです。
(確認の際は運よくリンク先に遷移したので最初は気付きませんでした...)すぐできる対処法
bxsliderのオプションの中にある
bxsliderオプションtouchEnabled: falseを追記すると解消できました。
この「touchEnabled」オプションは、スワイプ(フリック)時にスライドを移動させるためのオプションです。スマホとタブレットで見る時はtouchEnabledをtrueにする
先のtouchEnabledオプションをfalseのままだとスマホ・タブレットで見た時スワイプができなくなります。
スマートフォン・タブレットでスワイプできないと、ページャーやナビゲーションボタンをタップすることになります。
そうなると特にスマートフォンで見る時に、おそらく小さいボタンをタップすることになりますし、ユーザーにとってストレスになる可能性があります。
タッチデバイスではスワイプでスライドを移動できるように、@mitsuhiro_Kさんの対処法を元に少し変えて対処しました。
bxSliderがクリック出来なくなった時の応急処置$(function(){ let bxSliderConfig = { //使用しているサイトにあったオプション, touchEnabled: false }; let ua = navigator.userAgent; let sp = ua.indexOf('iPhone') > -1 || (ua.indexOf('Android') > -1 && ua.indexOf('Mobile') > -1); // スマートフォン let tab = ua.indexOf('iPad') > -1 ||(ua.indexOf('Macintosh') > -1 && 'ontouchend' in document) || ua.indexOf('Android') > -1; // タブレット // スマートフォンまたはタブレットの場合にtouchEnabledをtrueにする if (sp || tab) { bxSliderConfig.touchEnabled = true; } let slide = $('#slider ul').bxSlider(bxSliderConfig); });他参考サイト
bxSlider をつかったスライダーのリンクが機能しないときの対処方法
bxSliderのスライド内のリンクが効かなくなった際の対処方
bxsliderオプション参考サイト
- 投稿日:2020-08-01T12:25:00+09:00
JavaScriptで2つのJSONな配列の差分を抽出する
JSONの形で与えられた2つの配列を比較して、差分を抽出したい場合があります。
arr1 = [ {LawName: "民法", LawNo: "明治二十九年法律第八十九号"}, {LawName: "商法", LawNo: "明治三十二年法律第四十八号"}, {LawName: "刑法", LawNo: "明治四十年法律第四十五号"}, {LawName: "砂防法", LawNo: "明治三十年法律第二十九号"}, ... ]; arr2 = [ {LawName: "民法", LawNo: "明治二十九年法律第八十九号"}, {LawName: "商法", LawNo: "明治三十二年法律第四十八号"}, {LawName: "砂防法", LawNo: "明治三十年法律第二十九号"}, ... ];配列の差分が欲しければ、
Array.prototype.filter()
とArray.prototype.includes()
を組み合わせて抽出することが考えられる…のですが、うまくいきません。
→ 参考:js 二つの配列の差分を求める
失敗例arr1.filter(item => arr2.includes(item)); // return []
arr1[0]
とarr2[0]
は一見同じに見えますが、参照しているものが違うので、Array.prototype.includes()では「同じものは含まれていない」という扱いになってしまうわけですね。
(ちゃんと調べたわけではないですが、Javaのようにequals()をオーバーライドするやり方もできなさそうです。Array.prototype.sort()
のように比較関数を指定できれば良いのですが…。)
filter()
の中でオブジェクトが同値であるかを判定するコードをゴリゴリ書く、というのも一つの手段です。しかし、arr1の全ての要素についてarr2の全ての要素と比較するとなると、計算量が2つの配列の積になりそうな気がして嫌な感じです。文字列にして検索する
連想配列同士の比較には、文字列にして比較する、という手があります。(型を持つオブジェクトだと良くない気はしますが、今回は元がJSONだからへーきへーき。)
そこで、比較対象arr2
の配列を文字列にした上で、arr1
の各要素について、その要素の文字列表現がarr2
の文字列表現に含まれているかどうかによってfilter()
してみましょう。成功例var str_arr2 = JSON.stringify(arr2); //配列arr2の文字列表現 arr1.filter(item => str_arr2.indexOf(JSON.stringify(item))<0 ); //itemの文字列表現を検索。 // -> [{LawName: "刑法", LawNo: "明治四十年法律第四十五号"},...]→ 実装例:法技研六法:法令更新内容
ということで、法令リストの更新に対し、更新内容を表示できるようになりました。
Enjoy!
- 投稿日:2020-08-01T12:08:24+09:00
JavaScriptで正規表現にマッチしない部分を置換する
はじめに
JavaScriptには文字列置換の方法として
replace()
がありますが、これは正規表現に「マッチした部分」しか置換できません。では以下の場合どうすればいいでしょうか?文字列をHTMLエスケープせよ。ただし文字列中の文字参照はエスケープしてはならない。
ここで文字参照とは
- 文字実体参照 (
©
など)- 数値文字参照 (
♪
、♪
など)を指し、HTMLエスケープは
escapeHTML()
で行えるものとします。例えば、
"©<♪♪>"は
"©<♪♪>"に置換されます。
マッチする部分の正規表現
文字参照の正規表現は、
/&\w+;|&#\d+;|&#x[0-9a-fA-F]+;/
と表せますので、マッチする部分を置換するのであれば簡単です。例えば文字参照をそれが指す実際の文字に置き換えるのなら、const str = "©<♪♪>"; str.replace(/&\w+;|&#\d+;|&#x[0-9a-fA-F]+;/, toChar)のようにすればよいでしょう。(ただし文字参照を実際の文字に変換する関数
toChar()
は別途要定義)マッチしない部分の正規表現
マッチしない部分の正規表現が書ければ問題は解決ですが、ネットで探しても例がなく、なかなか難しそうです。マッチしない部分 + マッチした部分 の正規表現であれば、
/(?:(?!${pattern}).)*(?:${pattern})?/gと書けますので、これを利用することにします(上記はPerl風に正規表現に変数展開していますが、javascriptではこれはできないので一工夫必要です)。実際のケースでは「マッチする部分とマッチしない部分をそれぞれ置換する」という局面が多いのですが、それにも対応できそうです。
マッチしない部分 + マッチした部分 が取得できれば、次は
/^(.*?)(${pattern})?$/で、マッチしない部分 と マッチした部分 に分けることができます。
JavaScriptでの実装
これを実際にJavaScriptで実装すると以下のようになるでしょう。
const pattern = "&\\w+;|&#\\d+;|&#x[0-9a-fA-F]+;"; const regexp1 = new RegExp(`(?:(?!${pattern}).)*(?:${pattern})?`,'gi'); const regexp2 = new RegExp(`^(.*?)(${pattern})?$`,'i'); function replace(str = '') { let rv = ''; for (let chunk of str.match(regexp1)) { let [ , u, m ] = chunk.match(regexp2); if (u) rv += unmatch ? unmatch(u) : u; if (m) rv += match ? match(m) : m; } return rv; }
pattern
は文字列リテラルですので、\
が2つ必要なことに注意してください。
match()
はマッチしたとき、unmatch()
はマッチなかったときの置換関数です。モジュール化
この問題は度々発生するのでモジュール化しておきましょう。
replacer.jsmodule.exports = function(pattern, match, unmatch, opt = '') { const regexp1 = new RegExp(`(?:(?!${pattern}).)*(?:${pattern})?`,'g'+opt); const regexp2 = new RegExp(`^(.*?)(${pattern})?$`,opt); return function(str = '') { let rv = ''; for (let chunk of str.match(regexp1)) { let [ , u, m ] = chunk.match(regexp2); if (u) rv += unmatch ? unmatch(u) : u; if (m) rv += match ? match(m) : m; } return rv; } }元々の問題は、
const str = "©<♪♪>"; const replace = require('./replacer.js')("&\\w+;|&#\\d+;|&#x[0-9a-fA-F]+;", null, escapeHTML, 'i'); replace(str);で解くことができます。
- 投稿日:2020-08-01T11:29:54+09:00
JS 入力表示リスト
JSでテキストボックスに入力してボタンを押すと下にリスト表示。
すぐに忘れるので覚書しています。
もっといい方法があればコメント頂けたらありがたいです。<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>JS入力表示リスト</title> </head> <body> <form name="form01"> <p>メッセージを入力してください</p> <input type="text" id="message" name="message" size="40"> <input type="button" id="btn" value="OK" /> </form> <ul> </ul> <script> window.onload = function(){ document.getElementById('btn').onclick = function(){ var name = document.form01.message.value; console.log(name); const item2 = document.createElement('li'); item2.textContent = name; const ul = document.querySelector('ul'); ul.appendChild(item2); }; }; </script> </body> </html>
- 投稿日:2020-08-01T11:09:41+09:00
P5.js 日本語リファレンス(arc)
このページでは「P5.js 日本語リファレンス」 の arc関数を説明します。
arc()
説明文
画面に円弧を描きます。 x、y、w、h、start、stop のみで呼び出された場合、弧は描画され 開いた円セグメントとして塗りつぶされます。mode が指定されている場合、弧は開いた半円(OPEN)、閉じた半円(CHORD)、閉じたパイセグメント(PIE)として塗りつぶされます。原点は ellipseMode() で変更できます。
弧は常に楕円の始点から終点まで時計回りに描画されます。 TWO_PI をどちらかの角度に加算または減算してもそれらがどこに描画されるかは変わりません。開始と停止の両方が同じ場所にある場合、完全な楕円が描画されます。 Y軸は下方向に増加するため、角度は正のX方向から時計回りに回転することに注意してください。
構文
arc(x, y, w, h, start, stop, [mode], [detail])
パラメタ
x
Number:弧中心の楕円のx座標y
Number:弧中心の楕円のy座標w
Number:弧の楕円の幅h
Number:弧の楕円の高さstart
Number:ラジアンで指定された弧を開始する角度stop
Number:ラジアンで指定された弧を停止する角度mode
定数:弧の描画方法を決定するパラメータ。 CHORD、PIE または OPEN(オプション)detail
Number:WebGLモードのみのパラメータ。これは円弧の周囲を構成する頂点数を指定するためのものです。デフォルト値は25です。(オプション)例1
function setup() { createCanvas(400, 400); colorMode(HSB, 100); noFill(); let x = 100; let y = 110; ellipse(x, y, 4); // 中心点を描画 stroke(100, 100, 100); // 赤 arc(x, y, 150, 150, 0, HALF_PI); stroke(80, 100, 100); // 紫 arc(x, y, 160, 160, HALF_PI, PI); stroke(60, 100, 100); // 青 arc(x, y, 170, 170, PI, PI + QUARTER_PI); stroke(40, 100, 100); // 緑 arc(x, y, 180, 180, PI + QUARTER_PI, TWO_PI); }実行結果
https://editor.p5js.org/bit0101/sketches/TGz2ly_Gc
例2
function setup() { createCanvas(300, 400); let x = 50; let y = 50; // mode パラメタ別に円弧を描画 arc(x, y , 80, 80, 0, PI + QUARTER_PI); arc(x, y + 80 , 80, 80, 0, PI + QUARTER_PI, OPEN); arc(x, y + 160, 80, 80, 0 , PI + QUARTER_PI, CHORD); arc(x, y + 240, 80, 80, 0, PI + QUARTER_PI, PIE); }実行結果
https://editor.p5js.org/bit0101/sketches/LwZkL9UBE
例3
function setup() { createCanvas(300, 400, WEBGL); let x = -50; let y = -150; // detail パラメタを指定して円弧を描画 arc(x, y , 80, 80, 0, PI + QUARTER_PI, OPEN, 4); arc(x, y + 80 , 80, 80, 0, PI + QUARTER_PI, OPEN, 6); arc(x, y + 160, 80, 80, 0 , PI + QUARTER_PI, CHORD, 8); arc(x, y + 240, 80, 80, 0, PI + QUARTER_PI, PIE, 10); }実行結果
https://editor.p5js.org/bit0101/sketches/4gEPDcaTK
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-01T10:53:00+09:00
Functional Componentから、Fat Componentを防ぐ設計、Vue3のリアクティブまで!! Remote.vue#2 参加(登壇)レポート
2020/07/31 19:30からLAPRASさん主宰で開催されたRemote.vue#2の参加(登壇)レポートです。
勉強会のYouTube配信アーカイブはこちら。
https://www.youtube.com/watch?v=hUcQXgUxQVc&feature=youtu.be関連ツイートはこちら。
https://twitter.com/hashtag/remote_vue?src=hashtag_click&f=liveSFCで挑戦するFunctional Component (@FruitRiin)
スライド: https://speakerdeck.com/fruitriin/functional-component-challenge-at-sfc
動画開始位置: https://youtu.be/hUcQXgUxQVc?t=563
内容メモ:
・ Vue Functional Componentの紹介
・ 通常のComponentとFunctional Componentのパフォーマンス比較のライブデモ
・ Functional Componentの使用上の注意Vueいいぞおねいさん果物リンさんの発表。ちょうど当日Functional Componentを使ったコンポーネントのコードレビューをして「何もわからんw」ってなってたところだったので個人的にめちゃくちゃ勉強になりました。特に、Functional Componentと通常のコンポーネントのパフォーマンス比較のライブデモが秀逸で、明確にパフォーマンス差が出ているので驚きました。Atomic DesignのAtomのような小さいコンポーネントを、大量にレンダリングする際にはとても有効そうですね。
あと、全然関係ないんですが登壇中の落ち着きがすごくて「これがLT熟練者か..!!」と終始尊敬の眼差しでした。Fat ComponentにしないためのWebフロントエンド設計(@Philomagi)
スライド: https://speakerdeck.com/tooppoo/web-front-end-design-to-avoid-being-a-fat-component
動画開始位置: https://youtu.be/hUcQXgUxQVc?t=1925
内容メモ:
・ 実際にあったFat Componentの紹介(2500行のComponent!!!)
・ Fat Componentを作らないための設計指針
・ OOUIの話とても実用的な話。とりあえず最初の「2500行」のFat Componentの例に度肝を抜かれ、これは絶対防がなくてはならないと強く思いました。確かに、コンポーネントの分割だけでは
<script>
部分の振る舞いの分割にはならず、コンポーネントは分割されても<script>
部分は肥大化するというのはありがちですね。
今回のサンプルアプリケーションのようにView, Interaction, Modelに分けて設計し、知識・情報・振る舞いをコンポーネントから独立したものとして定義する例はFat Componentを防ぐ一つの解だと思います。Vueの設計への深い示唆を得ることが出来るプレゼンで何度もハッとするポイントがありました。私は設計が大の苦手なので、あと一時間くらい講義して欲しい気持ちでしたね。また折をみてスライド見返したいです。Ref vs Reactive Vue3 Composition APIのリアクティブ関数の探究(@KawamataRyo)
スライド: https://speakerdeck.com/kawamataryo/ref-vs-reactive-vue-composition-api-deep-in
動画開始位置: https://youtu.be/hUcQXgUxQVc?t=3806
内容メモ:
・ Vue3 Composition API, リアクティブの説明
・ refとreactiveの使い分けの指針。内部実装はどうなているのか。リアクティブの消失はどう防ぐのか。
・ 他のリアクティブ関数の紹介。はい。私ですw。自分で自分のレポート書くのも恥ずかしいのですが簡単に。Vue Composition APIのリアクティブ関数refとreactiveに着目して使い分けの話をしました。ref, reactiveの内部実装や、reactive関数で誰もが詰まるリアクティブの消失などなど。Vue Composition APIを使い始めてreactiveとrefの使い分けに迷ってる人などに参考になる内容かと思います。
..で後はただの感想なのですが、配信アーカイブを見返したら自分だけ緊張してとても早口になっているのが個人的にアレでした?。ちゃんと発表内容伝わっていたのかな??次回の発表では改善していきたいです。今回話した内容のリアクティブの諸々を自分で試したいと思ったら、「さくっとVue3をWebブラウザで試したい時に使えるTips」で紹介した方法でChrome devtoolsのconsoleからサクッと試せるので是非やってみてください。その他、今回発表出来ずおまけとして掲載した他のリアクティブ関数のについては「Vue Composition APIで使えるリアクティブ関連のAPI一覧にまとめています。
おわりに
以上「Functional Componentから、Fat Componentを防ぐ設計、Vue3のリアクティブまで!! Remote.vue 参加(登壇)レポート」でした。
雑感として、LAPRASの@nasumさんがいつ話をふられても、きれいに答えを返すので本当にすごいと思いました。あと、弊社のテックリードのツイートが取り上げられたのですが、私の方で上手く問題を説明できず最後の方しどろもどろに。。色々理解不足が露見したのでコード見返したいです。他、Vuexの話題でかなり盛り上がり、やはり皆色々な意味でVuex大好きなんだなぁと思いました。運営のnagasakoさん、@nasumさん、他の登壇者の方含めとても良い雰囲気で終始ざっくばらんに話せたので面白かったです。これは登壇しないと出来ない経験なので本当に参加して良かったなと思いました。
次回の開催も期待!!!また登壇挑戦したいです。
- 投稿日:2020-08-01T10:52:19+09:00
【JS/TS】Lookupテーブルを活用する
概要
戻り値の値が与えられた値に依存している際に、
if
やswitch
を使用して、下記のように対応する場面があるかと思います。Ifを使用した場合場合
const colorMapper = (color) => { if (color == "yellow") { return "黄"; } else if (color == "blue") { return "青"; } else if (color == "red") { return "赤"; } else { return "該当なし"; } }; colorMapper("yellow"); //=> 黄 colorMapper("pink"); //=> 該当なしSwitchを使用した場合
const colorMapper = (color) => { switch (color) { case "yellow": return "黄"; case "blue": return "青"; case "red": return "赤"; default: return "該当なし"; } }; colorMapper("yellow"); //=> 黄 colorMapper("pink"); //=> 該当なしLookupテーブルの活用
Lookupテーブルを使用することで、下記のように書くことが可能です。
これによって、コードの見易さの向上、また実行時間の短縮に繋がります。const colorsTable = { yellow: "黄", blue: "青", red: "赤", }; const colorMapper = (color) => colorsTable[color] || "該当なし"; colorMapper("yellow"); //=> 黄 colorMapper("pink"); //=> 該当なしちなみに、TypeScriptを使用すると下記のように書けます。
type ColorEn = "yellow" | "blue" | "red"; type ColorJa = "黄" | "青" | "赤"; const colorsTable: Record<ColorEn, ColorJa> = { yellow: "黄", blue: "青", red: "赤", }; const colorMapper = (color: ColorEn): ColorJa | "該当なし" => colorsTable[color] || "該当なし"; colorMapper("yellow"); //=> 黄 colorMapper("pink"); //=> 該当なし注意点
下記の記事でありますが、必ずしもLookupテーブルを使用することで実行時間の短縮が出来るわけでは無いようです。
参考
- 投稿日:2020-08-01T10:39:10+09:00
[JavaScript] reduce で配列を合成する際のベストプラクティス考
概要
- JavaScript で reduce により配列を合成する際、どの方法が速いのかを調べてみました。
比較対象
- 以下の実装を高階関数で書き替えるのを想定してます。
- 高階関数使用時の比較なので、「for 文の方が速いかどうか」は、今回の調査対象外です。
const info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] const results = [] for (const i in a) { results.push(...info[a[i]]) } console.log(results) // [11, 13, 15, 22, 24, 26, 33, 35, 37]候補
[].push()
;['a', 'b', 'c'] .map(key => info[key]) .reduce( (stack, it) => { stack.push(...it) return stack }, [] )
[].concat()
;['a', 'b', 'c'] .map(key => info[key]) .reduce((stack, it) => stack.concat(it))
[].push()
+,
;['a', 'b', 'c'] .map(key => info[key]) .reduce((stack, it) => (stack.push(...it), stack))
flatMap
;['a', 'b', 'c'].flatMap(key => info[key])計測
- 100万回ほど回してみました。
const info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] const m = 100 * 10000 console.time('push()') for (let i = 0; i < m; ++i) { a.map(key => info[key]) .reduce( (stack, it) => { stack.push(...it) return stack }, [] ) } console.timeEnd('push()') // push(): 1256.3330078125msconst info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] const m = 100 * 10000 console.time('concat()') for (let i = 0; i < m; ++i) { a.map(key => info[key]) .reduce((stack, it) => stack.concat(it)) } console.timeEnd('concat()') // concat(): 547.2890625msconst info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] const m = 100 * 10000 console.time('push() + ,') for (let i = 0; i < m; ++i) { a.map(key => info[key]) .reduce((stack, it) => (stack.push(...it), stack)) } console.timeEnd('push() + ,') // push() + ,: 1147.3388671875msconst info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] const m = 100 * 10000 console.time('flatMap') for (let i = 0; i < m; ++i) { a.flatMap(key => info[key]) } console.timeEnd('flatMap') // flatMap: 3049.98095703125ms結果
- 構文としては flatMap が一番スマートですが、速度では
concat()
による reduce が優る模様。優勝const info = { a: [11, 13, 15], b: [22, 24, 26], c: [33, 35, 37], } const a = ['a', 'b', 'c'] a.map(key => info[key]) .reduce((stack, it) => stack.concat(it))
さらに、コンマ演算子は reduce に渡す関数の構成で速度を僅かながら上げてくれる事もわかりました。
高階関数を使うのは必須として、さらに速い実装があれば教えて下さい!
(・ω・)< for が速いのは存じております故
- 投稿日:2020-08-01T09:06:52+09:00
[ js ] [ jQuery ] 外部リンクがクリックされた時、モーダルウィンドウをアラートとして表示させる
結局、先達の知恵をお借りして実装しましたが、そこに辿り着くのに手間取り、それまでは自分で実装していました。
なぜこれが採用されなかったのか、それはie11で機能しなかったからです。どうしても原因を見つけることができず、お蔵入りとなりました。
サイト内にある外部リンクがクリックされた時、モーダルウィンドウが立ち上がって、「本当に出ていきますか?否か?」を迫るプログラムです。
<a class="modalexternal-open" href="https://www.example.com/">サンプル</a> <div class="modalexternal"> <div class="modalexternal__bg modalexternal-close"></div> <div class="modalexternal__content"> <div class="modalexternal__content__txt">外部サイトへ遷移します。本当にいいですか?</div> <div class="modalexternal__yesno"> <a id="modalexternal__link" target="_blank">遷移する</a> <a class="modalexternal-close" href="">遷移しない</a> </div> </div> </div><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> <script> $(function(){ $('.modalexternal-open').on('click',function(){ var index = $('.modalexternal-open').index(this); var elements = document.querySelectorAll('.modalexternal-open'); var elementsArray = Array.from(elements); var target = document.getElementById('modalexternal__link') target.href = elementsArray[index].getAttribute('href'); $('.modalexternal').fadeIn(); return false; }); $('.modalexternal-close').on('click',function(){ $('.modalexternal').fadeOut(); return false; }); }); </script>.modal{ width:100%; height: 100vh; background: rgba(0,0,0,0.8); position:fixed; top: 0; } .modal_bg{ background: rgba(0,0,0,0.8); height: 100vh; position: absolute; width: 100%; } .modal_area{ background: #fff; left: 50%; padding: 40px; position: absolute; top: 50%; transform: translate(-50%,-50%); width: 60%; } .modal_area p{ padding:15px; } .modal_area button{ display:block; color: #8586AE; } .modal_area button:hover{ opacity: 0.6; }参考URL
JavaScriptでURLのパラメータやアンカーを判断して処理を変更する方法 | Tips Note by TAM
JavaScriptでモーダル(ポップアップ)を表示させる方法 | Tech dig
これなら簡単!JavaScriptでポップアップ表示・入力する方法を解説 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト
- 投稿日:2020-08-01T07:04:14+09:00
【npm】package, scriptsを利用した開発の際の知見や心得
概要
- JavaScriptでの開発において、npmを利用して得た知見や心得等のまとめ。
- 今回は、packageやscriptsに絞って記載。
package
package.json内の情報はできるだけ記述する
- こちらのメタ情報によって、Documentにもなりえる他、特定環境指定等、より多くの機能を与えることができるため。
- 例として下記のように指定することで、環境を制限して開発環境を統一することができる。
{ "engines": { "node": ">=10", "npm": "~5.0.0" } }package.json内へのコメントは、フィールドを利用する
- JSON形式でありコメントの対応が無いため、記述する場合は下記のようにフィールドを利用する形で情報を与える。
comment
と記述しておくことで、検索が容易。"comment": "...."ロックファイルは常にリポジトリにコミットする
package-lock.json
やyarn.lock
等のロックファイルは、リポジトリにコミットする必要がある。- 理由として、全開発者間で同一のバージョンと依存関係を維持するため。
本番環境へはnpm ciで行う
- 本番へのデプロイの際には、
npm ci
コマンドでインストールを行う。- 理由として、lockファイルに適した依存関係のクリーンインストールを行い、正確なバージョンを利用する必要があるため。
依存関係を適切かつ最新のものに保つ
- 脆弱性を防ぎ安全に保つため、常に依存関係を確認する。
- 下記のような手動・自動ツールを利用して、早期に調整する。
- npm-check-updates : 依存関係の確認・更新ツール
- npm-audit: 依存関係の自動修正コマンド。npm v6以上に内包。
- Dependabot : 脆弱性チェックの自動化ツール。無料。Github社。
- Snyk : 脆弱性チェックの自動化ツール。有料。
scripts
クロスプラットフォームを意識する
- 自身の環境だけではなく、「Windows,Linux,MacOS」で利用できるスクリプトを作成する。
- scripts内での
rm
等のUNIXコマンド利用は、Windowsでは対応が難しいため。- UNIXコマンドを利用したスクリプトを作成する場合、下記のようなパッケージを利用する。
- 下記、記述例
"scripts": { "remove": "rimraf ./dist", "copy": "cpx -C public/** dist" },複数コマンド実行は可能なものは並列で実行する
- 複数コマンド実行の場合、可能なものは並列で実行して、終了速度を上げる。
- 並列実行は、下記のようなパッケージを利用することで容易に可能。
- concurrently : 複数コマンド実行CLIツール
- npm-run-all : 複数コマンド実行CLIツール
同一コマンドで用途が違う場合、コロンで分ける
- ビルドや監視等、環境やファイルごとにコマンドを使い分ける場合は、下記のようにコロンをつけて分割してまとめる。
- ※下記の
run-s
コマンドは上記記載のnpm-run-all
のショートカット{ "scripts": { "build" : "run-s build:sass build:ts", "build:sass": "sass input.scss output.css", "build:ts" : "tsc main.ts", "watch" : "run-s watch:sass watch ts", "watch:sass": "sass --watch input.scss output.css", "watch:ts" : "tsc -w main.ts" } }
- 補足として、上記の
build
やwatch
コマンドは下記のように簡略化できる。
- 個人的にはアスタリスクよりも波括弧の方が、明示的かつ柔軟。
{ "scripts": { "build" : "run-s build:*", ... "watch" : "run-s watch:{sass,ts}", ... } }参考
- 投稿日:2020-08-01T04:47:11+09:00
Amplify UI Componentsの日本語化
概要
Nuxt+amplifyで認証周りを組むことを想定していますが、そのままVueを使ってもReactでもAngularでも可能かと思います。
こちらを日本語化していきます。
結論の前に
2020年の4月くらいにAmplify UI Componentsに新バージョンがリリースされた模様です。
具体的には
Latest@aws-amplify/ui-<framework>
と Legacy 版であるaws-amplify-<framework>
でして、現時点で Amplify hogehogeみたいな形でググると大体Legacy版のブログやQiita記事が出てきます。
最初よくわからなかったのでLegacy版でコーディングしていましたが、Latest版の恩恵が大きいので、後に続く方は必ずLatest版を使いましょう。
ちなみに自分は公式ドキュメントがすべて英語なため読み解くのが面倒だったので、楽をしようとしたらやり直す羽目になりました。日本語化について
Latest版では日本語化についてもちゃんと公式ドキュメントに書いていました。
https://docs.amplify.aws/ui/customization/translations/q/framework/vue
旧版では見受けられなかったので、新版の恩恵の一つかもしれません。実装
実際上記のドキュメントから自分がどのように実装しているかが下記になります。
ちなみに私はNuxtどころかVueを使うのが初めてで、ろくすっぽ公式ドキュメントを読んでいないのでベストプラクティスかどうかわかりません。良い方法あれば教えて下さい。
Nuxtで開発した場合、まずはamplify用の初期設定ファイルをplugin直下に作ると思うので、そちらに日本語化の処理を書きます。
多分vueで構築している場合はmain.js
です。amplify.jsimport Vue from 'vue' import Amplify, * as AmplifyModules from 'aws-amplify' import '@aws-amplify/ui-vue' import awsExports from '../src/aws-exports' import { vocabularies } from './dictionary.js' AmplifyModules.I18n.putVocabulariesForLanguage('ja', vocabularies) Vue.prototype.$Amplify = AmplifyModules Vue.use(AmplifyModules) Amplify.configure(awsExports)公式通りですね。
I18クラスのputVocabulariesForLanguage
メソッドを呼び出します。
第一引数に翻訳する言語をstringで、第二引数に実際の翻訳する対象の箇所と翻訳語の日本語をobjectで指定します。私は変換ファイルを別途pluginフォルダ内に作成しています。
第2引数を具体的に説明すると、上記画像の中でSign in to your account
という英語を日本語化したいとします。するとdictionary.js{[Translations.SIGN_IN_HEADER_TEXT]: 'ログイン',}このような形のObjectを作ります。
ではどの英語がどのkeyに対応しているのかといいますと、下記のリンクに書いています。
https://github.com/aws-amplify/amplify-js/blob/main/packages/amplify-ui-components/src/common/Translations.tsちなみにエラーメッセージ系は下記でした。
https://github.com/aws-amplify/amplify-js/blob/main/packages/auth/src/common/AuthErrorStrings.tsでは上記を元に辞書ファイルを作っていきましょう。
表示してほしくない文字列は空文字にしています。
※なお、Qiitaの仕様で括らないと表示されないためkeyをシングルクォーテーションでくくっていますが、実際は外してください。dictionary.jsimport { Translations } from '@aws-amplify/ui-components' export const vocabularies = { '[Translations.CREATE_ACCOUNT_TEXT]': 'アカウントの作成', '[Translations.EMAIL_LABEL]': 'メールアドレス *', '[Translations.EMAIL_PLACEHOLDER]': ' ', '[Translations.FORGOT_PASSWORD_TEXT]': 'パスワードをお忘れの場合', '[Translations.PASSWORD_LABEL]': 'パスワード *', '[Translations.PASSWORD_PLACEHOLDER]': ' ', '[Translations.RESET_PASSWORD_TEXT]': 'パスワードを変更する', '[Translations.SIGN_IN_ACTION]': 'ログイン', '[Translations.SIGN_IN_HEADER_TEXT]': 'ログイン', }このように翻訳用のObjectを用意してあげると、、、
成功しました。
placeholderとか不要なので空文字にしてます。学び
英語でもめんどくさがらずに、ちゃんと公式を読みにいきましょう。
読んだら読んだで大した量ではないです。Amplify UI Componentsは最新版を利用しましょう。
公式通りTutorialを進めたら最新版で構築するような流れになっています。お願い
一部エラーメッセージの定義ファイルがどこにあるのかわかりませんでした。
もし発見された方は教えていただけますと幸いです。エラーメッセージ例
Custom auth lambda trigger is not configured for the user pool.
An account with the given email already exists.
- 投稿日:2020-08-01T04:12:37+09:00
WebAssembly, Emscriptenを少しだけ触ってみた話
はじめに
2019年12月、WebAssemblyがweb標準になったというニュースをみました。
https://www.w3.org/2019/12/pressrelease-wasm-rec.html.enそれなら調べてみようと思い、やっと最近ちょっとだけ触ってみたというお話です。
あとQiitaの投稿の練習と、知見者にコメントでいろいろと教えていただきたいので書いてみました。WebAssemblyってなに?
アセンブラのようなバイナリ形式の低レベル言語です。
Web標準になったことにより、HTML, CSS, JavaScriptに続いて正式にブラウザで動く4つめの言語になりました。
すでに主要4ブラウザ(Chrome, Firefox, Edge, Safari)では動きます。なにがすごいのか
様々な言語に対応
「アセンブラ風のバイナリ形式」のため、そのまま実装するエンジニアはおそらくほとんどいません。
このWebAssemblyはC/C++, Go, TypeScriptなど様々な言語からコンパイルして生成することができます。
生成されたWebAssemblyはブラウザやnode.js上で動く、
つまりHTML/CSS, JS以外の言語で書かれた資産がブラウザで実行できることになります。調べてみると
C++で書かれていたゲームをブラウザで実行したりVimを移植したりする記事もでてきました。すごい。高速
とても速いらしいです(アバウト)。
詳しくはWebAssemblyはなぜ速いのかをご覧ください。
簡単に言うと
JSはダウンロードされてからブラウザ内部で解析され、その後最適になるようにコンパイルされて実行されますが、
WebAssemblyはすでにコンパイルされた中間言語なため実行までが速く、さらにより機械に適した書かれ方をしているため実行も高速ということらしいです。ガベージコレクションもないためメモリの手動管理が必要ですが、それも高速化の要因みたいです。すごい!というわけで触ってみた
これだけ面白そうな話がでてくると触ってみないわけにはいかないですね。
今回はEmscriptenを使ったC言語からのコンパイルを試してみました。
なぜ選んだのかは
1年間本番環境で WebAssembly ( by Emscripten )を使ってきた中で生じた問題とその解決策
の記事のアプリケーションのサポート範囲によってはどうしても WebAssembly ありきで考えられない場合があり、そういった場合は WebAssembly を使わないものにフォールバックする必要があり、その観点では、フォールバック先を用意できる AssemblyScript や Emscripten が良いのではないかと考えています(前者は AssemblyScript がというよりは、コンパイル対象が TypeScript であったりするので、そもそもそのまま純粋な JavaScript ソースを生成する経路がありますし、 Emscripten は WASM=0 オプションをコンパイル時に渡すだけで簡単に asm.js を利用した JavaScript ソースコードを生成することができます )。
に納得してしまったからです。
asm.jsに関してはここでは深く言及しませんが、asm.jsは、Javascriptの文法を保ったまま整数演算(int系)や単精度浮動小数点演算(float)を書けるようにして、 この文法に対応したスクリプト実行環境でJavascriptの数値演算を速くするための技術です。
引用:Javascriptの数値演算とasm.jsというものです。
C言語からのコンパイルとEmscripten
C言語からコンパイルする方法はいろいろありますが、
今回は最もメジャーだと考えられるEmscriptenを使用します。
Emscriptenはllvmやbinaryenを使用して、webassemblyと、その読み込みや設定のためのJSを生成します。
まずは公式からSDKが配布されているため、公式ページに従ってインストールしてみましょう。Emscriptenをインストールする前に準備をします。
私はMacを使用しているため、以降はMacユーザーを想定した説明になります、すみません。Emscriptenイントールの前に
公式にもありますが、インストール前に準備があります。
まずはEmscriptenのSDK(emsdk)はpythonを使用しているため、pythonをアップデートしろとのことです。 おそらく2.7.12以上がインストールされていれば問題なさそうです。次に以下のツールが入っていなければインストールを行います。
- Xcode Command Line Tools
- git
- cmake
cmakeはC系言語のビルドを自動化してくれるツールです。
インストールのための記事は調べてみればすぐに出ると思うので割愛させてください(あとで余裕あればリンクはります)Emscriptenインストール
あとは公式の手順に沿ってインストールしていきます。
任意のディレクトリで# emsdkの入手 git clone https://github.com/emscripten-core/emsdk.git # ディレクトリに移動 cd emsdk # Emscriptenのインストール ./emsdk install latest # Emscriptenのアクティベート(バージョンの指定) ./emsdk activate latest # PATHの設定 source ./emsdk_env.shを順番に実行し、インストールを行いましょう。
(設定を行うと一時的にnode.jsがemsdk内蔵のものを参照するようになります。他にnodeを使用する場合は注意。)Emscriptenを使ってみる
いよいよEmscriptenを使ってみます。まずはコンソールにhello worldを出してみます。
Emscriptenを使用してhtmlも一緒に生成するデモをよくみますが、今回は自分で用意したhtmlで読み込んでみましょう。以下のように簡単なディレクトリを作りましょう。
test ├── hello.c └── index.htmlそれぞれの中身はこんな感じ。すごくシンプル。
hello.jsはこれから生成します。hello.c#include <stdio.h> int main() { printf("Hello World\n"); }index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>emscripten test</title> </head> <body> <script src="./hello.js" ></script> </body> </html>Emscriptenでのコンパイル
testディレクトリ配下で以下のコマンドを実行します
emcc hello.c -o hello.js
-oオプションは生成ファイルの指定です。
これを行うと以下のようになったはずです。. ├── hello.c ├── hello.js ├── hello.wasm └── index.htmlこのhello.wasmがWebAssemblyで, hello.jsがその読み込みやメモリ設定などをしてくれています。
この状態でindex.htmlをサーバで読み込んでみましょう。(ローカルで開くとwasmが読み込めないので注意。)
consoleにhello worldが表示されていれば成功です!もし
wasm streaming compile failed: TypeError: Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.
のような警告が出る場合はサーバにwasmの設定がされていないため
その設定をする必要があります。
使っているサーバのMIME TYPE設定ファイルにwasmを書き加えましょう。Moduleオブジェクト
Emscriptenを使用して生成したjsを読み込むとグローバルにModuleオブジェクトが生成され、この中にいろんなものが入るみたいです。
ここはまだ調べきれてないので今後の課題ですね。
JSからC言語の関数を呼び出す
例えばボタンを押したなどのアクションがあった際に引数を渡してWebAssemblyで何かしらの計算させたかったとします。
今回は簡単な足し算をしてみましょう。C言語の設定
hello.cを次のように変更します。
hello.c#ifdef __EMSCRIPTEN__ #include <emscripten.h> #else #define EMSCRIPTEN_KEEPALIVE #endif #include <stdio.h> int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; } int main() { printf("Hello World\n"); }なにやら見慣れない文字が。
emscripten.h はemsciptenにあるヘッダーです。
Emscriptenはコンパイル時にdead code elimination (Tree Shaking的なやつ)を行っており、
main関数から辿れない関数は消去されてしまいます。
そのため関数名の前にEMSCRIPTEN_KEEPALIVEをつけてコンパイル時に書き出すように教える必要があります。
ifdefでヘッダ読み込みを分岐させているのは、Emscripten以外でこのコードを使用した場合でもエラーが出ないようにするためです。コンパイル
それでは再度コンパイルを行いましょう。
先ほどとは違い、次は以下のコマンドを実行してください。emcc hello.c -o hello.js -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']"これによってccallから関数を呼び出すことができます。
JSからの呼び出し
htmlを以下のように変更します。
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>emscripten test</title> </head> <body> <button onclick="add(1,2)">1 + 2 = ?</button> <script src="./hello.js" ></script> <script> const add = (a, b) => { const result = Module.ccall('add','number',['number'], [a, b]); console.log(result); } </script> </body> </html>これでボタンを押した際にjsで定義したadd関数が呼ばれるようになりました。
add関数の中をみていきましょう。const result = Module.ccall('add','number',['number', 'number'], [a, b]);グローバルに存在するModuleオブジェクト中のccallを使用することでWebAssemblyの関数を呼び出すことができます。
これは4つの引数を持ち、前から順番に
1. 使用したい関数名
2. 使用したことによって返ってくる型(number or string)
3. C言語の関数に渡す引数の型の配列(number or string)
4. C言語の関数に渡す引数の配列です。
サーバで開きボタンを押したらconsoleに3と表示されれば成功!
C言語からJSを呼ぶ
どうやらC言語のなかでJSを呼ぶこともできるみたいです。
まだ調べきれていないので、ここも今後の課題ですね。調べてみて・触ってみて思ったことを少しだけ
いろんな記事をみていると
Docker創業者が「もしもWebAssemblyとWASIが2008年に存在していたら、Dockerを開発する必要はなかった」
と言ったというものも出てきました。
WebAssemblyとRustが作るサーバーレスの未来私は調べてみた結果この技術にかなり期待しています。
例えば画像処理などのフロントエンド以外の分野で長けたエンジニアと協力し、より高度なウェブアプリケーションを実現したりもできるはずです。
それと同時に私たちフロントエンドエンジニアはHTML/CSS, JSだけでなく
幅広い言語やそれを用いて作られた資源についても知っていく必要があると思っています。
今後フロントエンドエンジニアやソフトウェアエンジニアの境界があまりなくなっていくのかなあとか。。完全に混ぜ合わさることはなさそうですが、行き来は今よりも簡単にできるようになりそうですよね。まだこれからどんどん発展していくであろう技術なので引き続き調べてみるつもりです
- 投稿日:2020-08-01T00:41:08+09:00
【javascript】Canvasを使ってみる
準備
<canvas id="sample">コンテキストオブジェクトを取得
let canvas = document.getElementById('sample'); let context = canvas.getContext('2d');getContextの第1引数に何を渡すかでコンテキストオブジェクトの種類が決まる。
渡す値 説明 2d 2次元グラフィックスの描画に使用 webgl、webgl2 3次元グラフィックスの描画に使用 図形を書く
長方形
長方形の関数
種類 説明 fillRect(x,y,width,height) 長方形(色付き) strokeRect(x,y,width,height) 長方形(枠線のみ) clearRect(x,y,width,height) 指定された領域を消去し、完全な透明にする 例//左から40上から60の位置に縦50横50の正方形を描く context.fillRect(40,60,50,50);参考