20220402のJavaScriptに関する記事は20件です。

コメントやコミットメッセージについてまとめる

どんな内容か 主観もまじっていますが、とても簡単なことでコード可読性があがります。 質の良いコメントやコミットメッセージを残してコードの歴史を追いやすくしたり、実装者の意図を伝えて新たに参画した人が読みやすくなります。 現場によって異なることもあるので参考程度に留めていただければと思います。 JSDoc 関数やクラスのコメントには//よりも/** ... */ を使用すると良いです。 カーソルを合わせた際に関数の説明欄が表示されるようになるので非常に便利です。 /** * 足し算するやつ * @param a 1つめの数値 * @param b 2つめの数値 * @return aとbの合計値 */ export const plus = (a: number, b: number) => { return a + b; }; シングルラインのコメントは以下のように使う 必ずコメントの前に空白スペースをいれる 主題の上に記載する function getType() { // set the default type to 'no type' const type = this.type || "no type"; return type; } 定数はコメントがあると助かる 定数がなぜその値なのか背景をかくと良いかと思います。 // 顧客要件により画面に表示する質問の回数は3回 まで などと背景を書く export const NUM_QUESTION = 3; よりシングルラインを強調したいときはアノテーションコメント コメントの先頭に FIXME や TODO をつけると、どのような問題を指摘しているのか、他の開発者がすぐに理解できるメリットがあります。 さらに VSCode では todo-tree などのプラグインを設定することでハイライトされ一覧で見ることが可能です。このアノテーションコメントを積極的に利用して、未実装の機能や対応しなければならないことの漏れを防ぐことができます。 以下に色々ありますが、個人的にはFIXME と TODO だけでだいたい大丈夫かと思います。 コメント 意味 FIXME: 既知の不具合あるコード。絶対に修正するという強い意志を感じる。 TODO: やるべきこと。FIXME より弱い。実装するべき機能。 HACK: リファクタリングしたい。要改善 。 REVIEW: 見直しが必要である、または見てください。 WARNING: 注意してください。 NOTE: 実装の意図やなぜこう書いたかを強調するときに書く。 コミットコメントの Prefix について angular プロジェクトの README を参考にすると良いと思います。 angular Commit Message Guidelines Prefix 意味 build: ビルドシステムや外部の依存関係に影響を与える変更(スコープ例:gulp、broccoli、npm) ci: CI 設定ファイルやスクリプトへの変更 docs: ドキュメンテーションのみの変更 feat: 新しい機能 fix: バグフィクス perf: パフォーマンスを向上させるためのコード変更 refactor: バグフィックスでも機能追加でもないコード変更 style: コードの意味に影響を与えない変更(空白、書式、セミコロンの欠落など) test: 不足しているテストの追加や既存のテストの修正 angular.js Commit Message Format Prefix 意味 feat: 新しい機能 fix: バグフィクス docs: ドキュメンテーションのみの変更 style: コードの意味に影響を与えない変更(空白、書式、セミコロンの欠落など) refactor: バグフィックスでも機能追加でもないコード変更 perf: パフォーマンスを向上させるためのコード変更 test: 不足しているテストの追加や既存のテストの修正 chore: ビルドプロセスやドキュメント生成などの補助ツールやライブラリの変更 他には 以下のようなものも見受けられます。 参考: Git のコミットメッセージの書き方 Prefix 意味 update: 機能修正(バグではない) add: 新規(ファイル)機能追加 remove: 削除(ファイル) merge: マージコミット emoji prefix 絵文字をコミットメッセージのプレフィックスに使うこともできます。 gitmojiで絵文字と対応する意味をあらかた検索できます。 リポジトリを見た際に絵文字があるので可愛さが向上します。 以下の記事においては絵文字のテンプレートをつくりコミットの際に使用できるようです。 Emoji で楽しく綺麗なコミットを手に入れる 最後に 保守性の高いコードを書く手法はいろいろとあるかと思いますが、これらは簡単なことなので今後とも心がけたいですね。 プロジェクトに応じて使い分けするのが良いかと思います。 参考文献 Airbnb JavaScript Style Guide
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

高速 scatter plot 描画(apache-arrow + regl 利用)

こんにちは。 apache-arrow (IPC) データをプロットしました1。regl (WebGL) を利用し高速描画処理を行なっています。 ただし、データの取得(ネットワークを通したダウンロード)は高速ではありません。したがって、この例のような大量データの場合(68 万点の scatter plot)、通常はおよそ 1 秒を要すようで、開始後一瞬で全データを描画完了とはいきません2。 ダウンロード進行中は、データは逐次分割されて取得され(10,000行単位)、その都度、データを追加して描画しています(ストリーム型処理)。 ソースおよび実行例はこちら、 regl + apache-arrow: fast WebGL scatter plot (bl.ocks.org) 参考:Efficiently loading massive D3 datasets using Apache Arrow (Chris Price, scottlogic.com) ↩ 同じデータをローカルファイルとして読み込むと、開始後ほぼ一瞬で全データを描画完了できます。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue3注目の新機能 Reactivity Transformとは?

初めに 最近Vueの情報収集をサボっていたのだが、どうやらいつの間にかReactivity Transformという新機能が追加されていたらしい。(僕が軽く調べた感じだと日本語の情報がほぼ無い) これはまだ実験的に導入されたもので、デフォルトで無効になっており、かつ今後破壊的な変更が入る可能性がある。 なので今すぐ学ぶ意味は薄いが、面白そうなのでちょっと触ってみる。 よければLGTMお願いします。 Reactivity Transformって何? 公式ドキュメント 簡単に言うとref()周りを短くシンプルに書けるエイリアス(公式はマクロと呼んでいる)を提供するものである。 例えば、数値等のプリミティブ値をリアクティブにする場合ref()を使うが、値を参照、変更するときいちいち.valueと書かなければいけないので、この部分が微妙に面倒であり直感的ではなかった。 vueのリアクティブシステムはProxyを利用しており、ランタイム上ではプリミティブ値をそのままリアクティブにするようなことはできないが、コンパイラでその問題を解決しようとしている。 これらのマクロを利用するにはimportは不要だが、デフォルトでoffになっているため、以下の設定が必要になる(vue3.2.25から利用可能) vite.config.js export default { plugins: [ vue({ reactivityTransform: true }) ] } TypeScript対応は型定義ファイルに /// <reference types="vue/macros-global" /> を追記するだけ。   どう使うか? さて実際にどう使うか見ていこう。 以下のサンプルコードは公式から引用。 script setup記法を使用。知らない方はぜひ私の記事をご覧ください。 <script setup> const count = ref(0) console.log(count.value) function increment() { count.value++ } </script> <template> <button @click="increment">{{ count }}</button> </template> これが <script setup> let count = $ref(0) console.log(count) function increment() { count++ } </script> <template> <button @click="increment">{{ count }}</button> </template> と書ける。 着目すべきは2点 ref()の代わりに$ref()を使っている $ref()から返却されたcountを直接変更、参照している まず、$ref()という見慣れない関数があるが、これは本物のjavascriptの関数ではなく、ビルド時にref()等のコードに置き換えられるマクロだ。 リアクティブ値に直接アクセスできるようになったので、より直感的になった。 ただし、変数宣言がconstからletになるため嫌う人は居そう(TypeScriptであれば型の一致は保証されるため大きな問題は無さそう?) ちなみに、こういったマクロは$refの他にも,$computed, $shallowRef, $customRef, $toRefが存在する。 $()を用いたrefオブジェクトの分割 refオブジェクトは通常の分割代入を使うとreactivityを失ってしまう。 ※reactivityとは、その値に変更を加えたとき、それに依存する値が自動的に更新されるような性質のことである。 よってtoRefsを使いReactivityを維持しながらプロパティを分割することができた。 そしてReactivity Transformでは$()を用いることにより、プレーンな値のまま分割されたプロパティに対してreactivityを付与することができる。 こちらも公式ドキュメントから引用 import { useMouse } from '@vueuse/core' const { x, y } = $(useMouse()) console.log(x, y) これは以下のコードにコンパイルされる import { toRef } from 'vue' import { useMouse } from '@vueuse/core' const __temp = useMouse(), x = toRef(__temp, 'x'), y = toRef(__temp, 'y') console.log(x.value, y.value) 分割代入された値がrefオブジェクトになっていることがわかる。 Reactivityの喪失 勘の良い人はなんとなく気づいているだろうが、これらのマクロで付与されたReactivityはいくつかのパターンで失われてしまうことがある。 関数へ渡されるパターン reactive変数が関数に渡される際にReactivityが失われるパターン. コードは公式から引用 function trackChange(x: Ref<number>) { watch(x, (x) => { console.log('x changed!') }) } let count = $ref(0) trackChange(count) // これは以下のようにコンパイルされる (関数定義省略) let count = ref(0) trackChange(count.value) これだとtrackChange内にはreactiveではないプレーンな値が渡されてしまい、reactivityが失われてしまう。 しかし、ちゃんとこれを以下のように修正すれば正常に動作する let count = $ref(0) trackChange($$(count)) 関数にわたす際に$$()で囲うことで、count.valueと展開されるのを回避できる。 関数から返却されるパターン 逆に関数内部からreactive変数を返却するときにもreactivityが失われてしまうことがある。 例によって公式から引用 function useMouse() { let x = $ref(0) let y = $ref(0) return { x, y } } これは以下のようにコンパイルされる (省略) return { x: x.value, y: y.value } const { count } = defineProps<{ count: number }>() passAsRef($$(count)) 当然これもvalueが露出してしまうためreactiveにはならない。 この場合も$$()を使用してこう書ける。 function useMouse() { let x = $ref(0) let y = $ref(0) // listen to mousemove... // fixed return $$({ x, y }) } パターンは違うが、.valueと展開しないように$$()でエスケープするだけ。 setup(props) { const __props_count = toRef(props, 'count') passAsRef(__props_count) } 最後に 実戦で使ってみなきゃ良し悪しはわかってこないかも? 正直わざわざコンパイル後のこと意識するくらいならこれまで通りでいい気がする? 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud Functions で GmailAPI で メールを送信する方法 [Javascript]

備忘録。 Google API を用意する まず の手順に沿って、認証情報の作成まで行います。途中、「スコープを追加または削除」の部分は readonly ではなく、send を選びます。 次に、 の 「OAuth 2.0 のための ID を得る」 に沿って、「Client ID」と「Client secret」と「Refresh token」と 「Refresh token」を 取得したのと同じページ から「Access Token」を取得します。 Cloud Functions を用意する を参考にして、Cloud Functions の有効化・関数の作成を行います (Python の部分は、Nodejs に書き換えて下さい)。 関数の作成が出来たら、作成した関数をクリックし、その中から「ソース」のタブを選択して、以下のコードを加えます。 クライアントID・クライアントシークレット・リフレッシュトークン・アクセストークンを適宜書き換えて下さい。 package.json { "name": "your-project-name", "version": "0.0.1", "dependencies": { "nodemailer": "^6.7.3" } } index.js const nodeMailer = require("nodemailer") exports.yourProject = (req, res) => { const transporter = nodeMailer.createTransport({ host: "smtp.gmail.com", port: 465, secure: true, auth: { type: "OAuth2", user: "your-email@gmail.com", clientId: "クライアントID", clientSecret: "クライアントシークレット", refreshToken: "リフレッシュトークン", accessToken: "アクセストークン", } const mailOptions = { from: "your-email@gmail.com", to: "to-email@sample.com", subject: "Test Subject", text: "Test Text", } transporter.sendMail(mailOptions) .then(() => { res.status(200).send(response) }) .catch(e => { res.status(500).send(e) }) } これで、Cloud Functions から Gmail を送信することができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravelでyoutubeの料理動画を管理するアプリを作ってみた。

laravelを使ってYoutube上にある料理動画を管理するサービスを作成しました。 Youtubeには様々な料理動画が日々アップされていますが、実際に作ってみてよかったものをストックしたり、 少し自分好みにアレンジした時のメモを残したいと思ったので、当サービスを作ってみました。 セキュリティ面など至らない点が多いとは思いますが、興味があれば使ってみていただけると幸いです。 ⇩作成したサービス 自己紹介 PHPを本格的に学習し始めて3ヶ月目の駆け出しエンジニア。前職はインフラ系で現在Webエンジニアになるため転職活動中です。 使用技術 フロントエンド Javascript Jquery Bootstrap バックエンド PHP(Laravel8) YoutubeAPI Mysql インフラ AWS Git 認証機能はLaravelにデフォルトで備わっているlaravel-authを使用しました。 また、AWSはEC2でサーバーをたて、データベースにRDS、ドメインの割り当てにRoute53(ドメインはお名前ドットコムで取得)、メールの送信にAmazonSESを使用しています。 作成期間 2022年2月下旬~2022年3月下旬の約一ヶ月間。 使い方 会員登録画面 ログイン画面 Home画面 ライブラリ 「レシピ本を見る」⇒ 自分のレシピ本を作成する。フォルダ分けしてレシピを保存するイメージ。 「保存したレシピ」⇒ 自分が保存したレシピをすべて表示する。検索可能。ここからもレシピを追加できる。 レシピを探す 「みんなのレシピ」⇒ 他のユーザーが作成したレシピを探す。 「動画から探す」⇒ 他のユーザーが追加したレシピをYoutubeの動画単位で探す。平均評価順など並び替え可能。動画をクリックすると、動画再生ページに遷移し、レシピの追加が可能になる。 Library画面 作成したレシピ本一覧。「+ Create New Recipeboook」でレシピ本を新規作成できる。 Book画面 作成したレシピ本の内容を表示する。右下の「+」ボタンを押すと、、、 レシピ作成用のモーダルが表示される。ここに追加したいYoutube動画のURLを入力し、「動画のタイトルとサムネイルを取得」をクリックすると、、、 Youtubeからタイトルとサムネイルが取得でき、「追加」ボタンをクリックしてレシピを追加できる。 レシピの追加方法は以上。その他のページも基本的にはこれと似たような使い方になる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IN演算子 JavaScript

用途 オブジェクトに存在するかどうかを調べる 配列に対して要素番号が存在するかどうか調べる 使用方法 オブジェクトに存在するかどうかを調べる var hoge = { a : "aです" } console.log("aです" in obj); //true console.log("bです" in obj); //false 文言 in 値 というように記述すると、文言 が 値 に存在している場合は true が、存在しない場合は false が返ってくる。 配列に対して要素番号が存在するかどうか調べる var hoge = ["a", "b", "c"]; console.log(0 in hoge); //true console.log(1 in hoge); //true console.log(2 in hoge); //true console.log(3 in hoge); //false     この記事は以下の情報を参考にして執筆しました。 https://codaholic.org/?p=1101
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript jQuery の基礎学習

はじめに 今回は、JavaScriptとjQuery についての基礎学習をしたため、アウトプットするために記事を書きました。 jQueryの記述方法 $('.item').css('color', 'red'); 基本的にはこの記述方法になる。 $(操作したい部分のクラスやIDを記述).処理する方法(処理する内容) 上記のように部分ごとに記述する内容は決まっており、クウォートなどの書き忘れに注意すること。 クラスの指定→. IDの指定→# この二つが基本で他のものはほとんど使用しなかった。 jQueryのアクション click = 指定要素上で左クリック時に発生。 dblclick = 指定要素上でダブルクリック時に発生。 ダブルクリックした際もclickイベントは発生する点に注意。 contextmenu = 指定要素上でマウス右ボタンを押した際に発生。 コンテキストメニューを表示させたくない場合は、このイベントでreturn falseやpreventDefaultする。 mousedown = 指定要素上で左or右ボタンを押した際に発生。 mouseup = 指定要素上で左or右ボタンを離した際に発生。 jQueryのフォームからの値の取り出し <body> <input type="text" id="value"> <input type="button" id="button" value="ボタン"> </body> <script> $(function(){ $('#button').on('click',function(){ alert($('#value').val()); }); }); </script> 上記の処理は、フォームに送信された値をアラートとしてブラウザ上で表示する処理になっており、($('#value').val());この部分でフォームから送信された値を取り出している。 ※.valはvalue属性を持った値を取り出すことができる。 まとめ 今回は簡単に学習のアウトプットをしてみました。 初学者になりますので、何か誤った表現をしているところなどあれば、コメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【超初学者】JavaScriptのfunctionとは

騙し騙しやっていたので備忘録 間違いがあればご指摘ください functionとは? https://kitsune.blog/function こちらの方がわかりやすく説明してくださっています 関数と呼ばれる,何かをしたら何かを返してくれるプログラムである 例えば,現在の時間を00:00:00のように表示させたいとき, var now = new Date(); // Dateオブジェクトを作る var hours = now.getHours(); // DateオブジェクトにgetHoursメソッドを充てることで現在の時を取得 var minutes = now.getMinutes(); // DateオブジェクトにgetMinutesメソッドを充てることで現在の分を取得 var seconds = now.getSeconds(); // DateオブジェクトにgetSecondsメソッドを充てることで現在の秒を取得 // hours が10未満だった場合0をつける if (hours < 10) { seconds = '0' + seconds; } // minutesが10未満だった場合0をつける if (minutes < 10) { seconds = '0' + seconds; } // secondsが10未満だった場合0をつける if (seconds < 10) { seconds = '0' + seconds; } このようにするところだが,これをfunctionを使って, 10未満の場合0をつけるという同様の処理をしているところをメソッドにしたい if (seconds < 10) { seconds = '0' + seconds; } この部分を, var addZero = function(value) { if (value < 10) { value = '0' + value; } return value; } このように変更し, var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds(); この部分のhours,minutes.secondsを下記のように再代入する var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds(); var addZero = function(value) { if (value < 10) { value = '0' + value; } return value; // "戻り値"と呼ばれる valueとして値を返すという意味 } hours = addZero(hours); // 再代入 minutes = addZero(minutes); // 再代入 seconds = addZero(seconds); // 再代入 解説 var addZero = function(value) { この部分のvalueとは何か? これはパラメーターと呼ばれるものであり, function内の処理を代入された文字列です 後で定義される hours = addZero(hours); // 再代入 minutes = addZero(minutes); // 再代入 seconds = addZero(seconds); // 再代入 この部分で, すでにnow.getHours(); now.getMinutes(); now.getSeconds(); されていたhours minutes seconds 変数を,valueに代入するという意味である よって,function内の処理を代入された文字列"value"に,hours,minutes,seconds を代入することにより, hours,minutes,secondsにもfunction内の処理が適応されることになる 備考 パラメータは複数設定できる var addZero = function(value, param2, param3) { のように幾つでも追加できる その場合,下記のようにパラメータと同じ数だけ追加する必要がある hours = addZero(hours, 123, abc); getTimeメソッドで時分秒全て取得できる var hours = now.getTime(); ただし出力されるのは,1970年1月1日0時0分0秒からの経過秒数となっているので変換が必要
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Denoにタスクランナーが搭載された件(`deno task`コマンド)

Deno1.20では、タスクランナーが本体に入りました。基本的にはnpm scriptsと同じなのですが、デフォルトでクロスプラットフォーム対応になっているなど、違う所もあります。 deno task コマンドの使い方 deno.json(c)でタスクの内容を設定します。 ※deno.json(c)の構文についてはこちらの記事を参照してください。 deno.jsonc(例) { "tasks": { // "<タスク名>": "<タスク内容>" の形で定義する // deno task hello "hello": "deno eval \"console.log('hello')\"", // deno task world "world": "deno eval \"console.log('world')\"", // deno task args hello world # output: ["hello", "world"] "args": "deno eval \"console.log(Deno.args)\"", "echo": "echo hello world", "nesting": "echo $(deno eval \"console.log('hello world')\")", "concat1": "echo 1 && echo 2", "concat2": "deno eval \"Deno.exit(1)\" || echo 2", "pipe": "echo hello world | deno eval \"Deno.stdin.readable.pipeTo(Deno.stdout.writable)\"", "var": "VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"", "export": "export VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"" } } このdeno.jsonを置いたディレクトリより下層のディレクトリでは、定義したタスクが有効になります。 タスク名として使えるのは英数字+コロン(1文字目は必ず英字)です。(^[A-Za-z][A-Za-z0-9_\\-:]*$) 以下、このdeno.jsonを使って解説していきます。 タスクを実行 ターミナルでdeno task <タスク名>というコマンドを打つと、タスクが実行されます。 > deno task hello Warning deno task is unstable and may drastically change in the future Task hello deno eval "console.log('hello')" hello タスク名の後に引数を渡すと、その引数はそのままコマンドに渡されます。 > deno task args hello world # hello worldが引数の部分 Warning deno task is unstable and may drastically change in the future Task args deno eval "console.log(Deno.args)" "hello" "world" [ "hello", "world" ] タスクのリストを表示 ターミナルでdeno taskコマンド(引数無し)を打つと、タスクのリストが表示されます。 > deno task Warning deno task is unstable and may drastically change in the future Available tasks: - args deno eval "console.log(Deno.args)" - concat1 echo 1 && echo 2 - concat2 deno eval "Deno.exit(1)" || echo 2 - echo echo hello world # ...(以下略) タスクの文法 コマンドの連結や入れ子がサポートされています。 文法 意味 <command1> && <command2> command1が成功(exit code 0)したらcommand2を実行するecho hello && echo world <command1> || <command2> command1が失敗(exit code 1)したらcommand2を実行するdeno eval 'Deno.exit(1)' || echo hello <command1> ; <command2> command1が終了したら成功・失敗に関係なくcommand2を実行するecho hello ; echo world <command1> & <command2> command1とcommand2を並列に実行するecho hello & echo world <command1> | <command2> command1のstdout出力をcommand2にパイプするecho hello world | deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' <command1> |& <command2> command1のstdout出力とstderr出力をcommand2にパイプするdeno eval 'console.log(1); console.error(2);' |& deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' VAR_NAME=<val> シェル変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できない)VAR=hello && export $VAR export VAR_NAME=<val> 環境変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できる)export VAR=hello && deno eval \"console.log(Deno.env.get('VAR'))\" $VAR_NAME シェル変数や環境変数を使用するVAR=hello && export $VAR $(<command>) コマンドを入れ子にするecho $(deno eval 'console.log(1)') ! <command> コマンドの終了コードを無視し、必ず成功扱いにする! deno eval 'Deno.exit(1)' 現在は上記のような構文がサポートされています。将来的にはリダイレクト(command > file_name)やglob(./*.js)がサポートされる予定です。 クロスプラットフォーム対応 npm scriptsの場合、Windows/Linux/Mac OSの間でクロスプラットフォームなコマンドを書くためにはshxなどのパッケージをインストールする必要がありました。 (例えばrmなどはwindowsに存在しないので、このパッケージを通して使う必要がある) 一方、deno taskではクロスプラットフォーム対応のコマンドが最初から組み込まれています。 Deno1.20時点では以下のコマンドがデフォルトで組み込まれており、Windowsでも追加パッケージ無しで使えるようになっています。 cp : ファイルをコピーする mv : ファイルを移動する rm : ファイルを削除する(例:rm -rf [FILE]...) mkdir : ディレクトリを作成する(例:mkdir -p DIRECTORY...) pwd : カレントディレクトリを表示する sleep : n秒待つ(例:sleep 1) echo : 文字列を表示する exit : シェルからexitする 使い方については、同名のUnixコマンドと同じです。 これらのコマンドがなぜWindowsでも使えるのかというと、deno_task_shellリポジトリでシェルごと実装されているからです。もし他に追加してほしいコマンドがあれば、このリポジトリでissueを開くと追加してくれるそうです。 LinuxやMacでこの組み込みコマンドではなくOSのコマンドを使用したい場合は、shコマンドを使います(例:sh -c cp source destination) まとめ deno.json(c)でタスクを使うとdeno taskコマンドから利用可能 デフォルトでクロスプラットフォーム対応している 従来は、Denoのタスクランナーとしてvelociraptorやmakefileが使われていました。一方で、Deno本体にクロスプラットフォームなタスクランナーを搭載してほしいという要望もあり、deno taskが実装されました。 最近では標準ライブラリにdotenvモジュールが追加されるなど、基本的に全員がインストールすることになるツールはデフォルトで使えるようになっているのがDenoの嬉しい所です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Denoにタスクランナーが搭載された(`deno task`コマンド)

Deno1.20では、タスクランナーが本体に入りました。基本的にはnpm scriptsと同じなのですが、デフォルトでクロスプラットフォーム対応になっているなど、違う所もあります。 deno task コマンドの使い方 タスクの設定 まず、deno.json(c)でタスクの内容を設定します。 ※deno.json(c)の構文についてはこちらの記事を参照してください。 deno.jsonc(例) { "tasks": { // "<タスク名>": "<タスク内容>" の形で定義する // deno task hello "hello": "deno eval \"console.log('hello')\"", // deno task world "world": "deno eval \"console.log('world')\"", // deno task args hello world # output: ["hello", "world"] "args": "deno eval \"console.log(Deno.args)\"", "echo": "echo hello world", "nesting": "echo $(deno eval \"console.log('hello world')\")", "concat1": "echo 1 && echo 2", "concat2": "deno eval \"Deno.exit(1)\" || echo 2", "pipe": "echo hello world | deno eval \"Deno.stdin.readable.pipeTo(Deno.stdout.writable)\"", "var": "VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"", "export": "export VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"" } } このdeno.jsonを置いたディレクトリより下層のディレクトリでは、定義したタスクが有効になります。 タスク名として使えるのは英数字+コロン(1文字目は必ず英字)です。(^[A-Za-z][A-Za-z0-9_\\-:]*$) 以下、このdeno.jsonを使って解説していきます。 タスクを実行 ターミナルでdeno task <タスク名>というコマンドを打つと、タスクが実行されます。 > deno task hello Warning deno task is unstable and may drastically change in the future Task hello deno eval "console.log('hello')" hello タスク名の後に引数を渡すと、その引数はそのままコマンドに渡されます。 > deno task args hello world # hello worldが引数の部分 Warning deno task is unstable and may drastically change in the future Task args deno eval "console.log(Deno.args)" "hello" "world" [ "hello", "world" ] タスクのリストを表示 ターミナルでdeno taskコマンド(引数無し)を打つと、タスクのリストが表示されます。 > deno task Warning deno task is unstable and may drastically change in the future Available tasks: - args deno eval "console.log(Deno.args)" - concat1 echo 1 && echo 2 - concat2 deno eval "Deno.exit(1)" || echo 2 - echo echo hello world # ...(以下略) タスクの文法 コマンドの連結や入れ子がサポートされています。 文法 意味 <command1> && <command2> command1が成功(exit code 0)したらcommand2を実行するecho hello && echo world <command1> || <command2> command1が失敗(exit code 1)したらcommand2を実行するdeno eval 'Deno.exit(1)' || echo hello <command1> ; <command2> command1が終了したら成功・失敗に関係なくcommand2を実行するecho hello ; echo world <command1> & <command2> command1とcommand2を並列に実行するecho hello & echo world <command1> | <command2> command1のstdout出力をcommand2にパイプするecho hello world | deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' <command1> |& <command2> command1のstdout出力とstderr出力をcommand2にパイプするdeno eval 'console.log(1); console.error(2);' |& deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' VAR_NAME=<val> シェル変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できない)VAR=hello && export $VAR export VAR_NAME=<val> 環境変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できる)export VAR=hello && deno eval \"console.log(Deno.env.get('VAR'))\" $VAR_NAME シェル変数や環境変数を使用するVAR=hello && export $VAR $(<command>) コマンドを入れ子にするecho $(deno eval 'console.log(1)') ! <command> コマンドの終了コードを無視し、必ず成功扱いにする! deno eval 'Deno.exit(1)' 現在は上記のような構文がサポートされています。将来的にはリダイレクト(command > file_name)やglob(./*.js)がサポートされる予定です。 クロスプラットフォーム対応 npm scriptsの場合、Windows/Linux/Mac OSの間でクロスプラットフォームなコマンドを書くためにはshxなどのパッケージをインストールする必要がありました。 (例えばrmなどはwindowsに存在しないので、このパッケージを通して使う必要がある) 一方、deno taskではクロスプラットフォーム対応のコマンドが最初から組み込まれています。 Deno1.20時点では以下のコマンドがデフォルトで組み込まれており、Windowsでも追加パッケージ無しで使えるようになっています。 cp : ファイルをコピーする mv : ファイルを移動する rm : ファイルを削除する(例:rm -rf [FILE]...) mkdir : ディレクトリを作成する(例:mkdir -p DIRECTORY...) pwd : カレントディレクトリを表示する sleep : n秒待つ(例:sleep 1) echo : 文字列を表示する exit : シェルからexitする 使い方については、同名のUnixコマンドと同じです。 これらのコマンドがなぜWindowsでも使えるのかというと、deno_task_shellリポジトリでシェルごと実装されているからです。もし他に追加してほしいコマンドがあれば、このリポジトリでissueを開くと追加してくれるそうです。 LinuxやMacでこの組み込みコマンドではなくOSのコマンドを使用したい場合は、shコマンドを使います(例:sh -c cp source destination) まとめ deno.json(c)でタスクを使うとdeno taskコマンドから利用可能 デフォルトでクロスプラットフォーム対応している 従来は、Denoのタスクランナーとしてvelociraptorやmakefileが使われていました。一方で、Deno本体にクロスプラットフォームなタスクランナーを搭載してほしいという要望もあり、deno taskが実装されました。 最近では標準ライブラリにdotenvモジュールが追加されるなど、基本的に全員がインストールすることになるツールはデフォルトで使えるようになっているのがDenoの嬉しい所です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Deno 1.20〜】公式タスクランナー、`deno task`コマンドの使い方

タスクランナーとは、コマンドに対してショートカットを設定しておくことができる機能です。サーバー立ち上げやビルド用のコマンドをあらかじめタスクランナーに設定しておくことで、開発体験を向上することができます。Node.jsではnpm scriptsが一般的に使われています。 Deno1.20では、タスクランナーがDeno CLI本体に入りました。基本的にはnpm scriptsと同じ機能なのですが、デフォルトでクロスプラットフォーム対応になっているなど、違う所もあります。 deno task コマンドの使い方 タスクの設定 まず、deno.json(c)でタスクの内容を設定します。 ※deno.json(c)の構文についてはこちらの記事を参照してください。 deno.jsonc(例) { "tasks": { // "<タスク名>": "<タスク内容>" の形で定義する // deno task hello "hello": "deno eval \"console.log('hello')\"", // deno task world "world": "deno eval \"console.log('world')\"", // deno task args hello world # output: ["hello", "world"] "args": "deno eval \"console.log(Deno.args)\"", "echo": "echo hello world", "nesting": "echo $(deno eval \"console.log('hello world')\")", "concat1": "echo 1 && echo 2", "concat2": "deno eval \"Deno.exit(1)\" || echo 2", "pipe": "echo hello world | deno eval \"Deno.stdin.readable.pipeTo(Deno.stdout.writable)\"", "var": "VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"", "export": "export VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"" } } このdeno.jsonを置いたディレクトリより下層のディレクトリでは、定義したタスクが有効になります。 タスク名として使えるのは英数字+コロン(1文字目は必ず英字)です。(^[A-Za-z][A-Za-z0-9_\\-:]*$) 以下、このdeno.jsonを使って解説していきます。 タスクを実行 ターミナルでdeno task <タスク名>というコマンドを打つと、タスクが実行されます。 > deno task hello Warning deno task is unstable and may drastically change in the future Task hello deno eval "console.log('hello')" hello タスク名の後に引数を渡すと、その引数はそのままコマンドに渡されます。 > deno task args hello world # hello worldが引数の部分 Warning deno task is unstable and may drastically change in the future Task args deno eval "console.log(Deno.args)" "hello" "world" [ "hello", "world" ] タスクのリストを表示 ターミナルでdeno taskコマンド(引数無し)を打つと、タスクのリストが表示されます。 > deno task Warning deno task is unstable and may drastically change in the future Available tasks: - args deno eval "console.log(Deno.args)" - concat1 echo 1 && echo 2 - concat2 deno eval "Deno.exit(1)" || echo 2 - echo echo hello world # ...(以下略) タスクの文法 コマンドの連結や入れ子がサポートされています。 文法 意味 <command1> && <command2> command1が成功(exit code 0)したらcommand2を実行するecho hello && echo world <command1> || <command2> command1が失敗(exit code 1)したらcommand2を実行するdeno eval 'Deno.exit(1)' || echo hello <command1> ; <command2> command1が終了したら成功・失敗に関係なくcommand2を実行するecho hello ; echo world <command1> & <command2> command1とcommand2を並列に実行するecho hello & echo world <command1> | <command2> command1のstdout出力をcommand2にパイプするecho hello world | deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' <command1> |& <command2> command1のstdout出力とstderr出力をcommand2にパイプするdeno eval 'console.log(1); console.error(2);' |& deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)' VAR_NAME=<val> シェル変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できない)VAR=hello && export $VAR export VAR_NAME=<val> 環境変数VAR_NAMEに値を代入する(値は生成したプロセス内で利用できる)export VAR=hello && deno eval \"console.log(Deno.env.get('VAR'))\" $VAR_NAME シェル変数や環境変数を使用するVAR=hello && export $VAR $(<command>) コマンドを入れ子にするecho $(deno eval 'console.log(1)') ! <command> コマンドの終了コードを無視し、必ず成功扱いにする! deno eval 'Deno.exit(1)' 現在は上記のような構文がサポートされています。将来的にはリダイレクト(command > file_name)やglob(./*.js)がサポートされる予定です。 クロスプラットフォーム対応 npm scriptsの場合、Windows/Linux/Mac OSの間でクロスプラットフォームなコマンドを書くためにはshxなどのパッケージをインストールする必要がありました。 (例えばrmなどはwindowsに存在しないので、このパッケージを通して使う必要がある) 一方、deno taskではクロスプラットフォーム対応のコマンドが最初から組み込まれています。 Deno1.20時点では以下のコマンドがデフォルトで組み込まれており、Windowsでも追加パッケージ無しで使えるようになっています。 cp : ファイルをコピーする mv : ファイルを移動する rm : ファイルを削除する(例:rm -rf [FILE]...) mkdir : ディレクトリを作成する(例:mkdir -p DIRECTORY...) pwd : カレントディレクトリを表示する sleep : n秒待つ(例:sleep 1) echo : 文字列を表示する exit : シェルからexitする 使い方については、同名のUnixコマンドと同じです。 これらのコマンドがなぜWindowsでも使えるのかというと、deno_task_shellリポジトリでシェルごと実装されているからです。もし他に追加してほしいコマンドがあれば、このリポジトリでissueを開くと追加してくれるそうです。 LinuxやMacでこの組み込みコマンドではなくOSのコマンドを使用したい場合は、shコマンドを使います(例:sh -c cp source destination) まとめ deno.json(c)でタスクを使うとdeno taskコマンドから利用可能 デフォルトでクロスプラットフォーム対応している 従来は、Denoのタスクランナーとしてvelociraptorやmakefileが使われていました。一方で、Deno本体にクロスプラットフォームなタスクランナーを搭載してほしいという要望もあり、deno taskが実装されました。 これからは3rd party製のツールに頼ることなく、タスクランナーを使うことができます。 最近では標準ライブラリにdotenvモジュールが追加されるなど、基本的に全員がインストールすることになるツールはデフォルトで使えるようになっているのがDenoの嬉しい所です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS スクロールするとヘッダーのナビが画面上部に固定されついてくる方法

今回はヘッダー内のナビゲーションが、スクロールすることで画面上部に接触した際に、 画面上部に固定される方法をjQueryを使用せずにやっていきます。 (完成系コードは最下部) HTMLコード <body> <header> <h1 id="headerH1">タゴ'sクリエイト</h1> <nav> <p id="headerFixed">Global-Navigation</p> </nav> </header> <main> <div> <h2>Content</h2> </div> <div> <h2>Content</h2> </div>              ・              ・              ・              ・ </main> </body> とりあえずHTMLとCSSを使用して写真のようなものをブラウザに表示しました。 この「Global-Navigation」に対して、 下へスクロールすると画面上部にくっついて固定されるものをJSで記述していきます。 JSコード window.addEventListener('load',fixedCheck); //1 window.addEventListener('resize',fixedCheck); //2 window.addEventListener('scroll',fixedCheck,{passive:true}); //3 function fixedCheck(){ //4 let globalN=document.getElementById('headerFixed'); //5 let fixedJudge=globalN.getBoundingClientRect().top; //6 if(fixedJudge<=0){ //7 globalN.classList.add('fixed'); //8 } } CSSコード .fixed{ position: fixed; width: 100%; top: 0; left: 0; } この記述で画像の様な感じになります。 それでは「//番号」の順で1行ずつ説明していきます。 1、まず「addEventListener」で、ウィンドウをロードした時に「fixedCheck」関数を呼び出します。(この「fixedCheck」は後で説明しますが、大まかに言うと「HTMLの要素にclassを追加するか判定」という意味です) 2、次にまた「addEventListener」を使い、今度はウィンドウの画面サイズを変更した時に「fixedCheck」関数を呼び出します。 3、またまた「addEventListener」を使い、ウィンドウをスクロールした時にも「fixedCheck」関数を呼び出します。 ここで第三引数に 4、次は先ほどの「fixedCheck」関数を記述していきます。 5、まずはHTMLのグローバルナビ(今回は「headerFixed」)を「getElementById」で取得し、変数「globalN」変数に代入します。 6、次に「getBoundingClientRect().top」で「globalN」要素の上辺を基準とする、ブラウザ上の高さ位置を取得し、「fixedJudge」変数へ代入します。 ここで「getBoundingClientRect」について説明です。 これは「要素.getBoundingClientRect().top」とすることで、 (今回Xは「top」を指定してますが、他の指定種類については後述します) 要素のボックス(border、padding含む)の上辺の座標が、ブラウザの表示部分(ビューポート)の基準点である左上(左上が「0,0」となっている)を基準として、どの位置にいてるかを数値として取得できます。 この「top」の他にも「bottom,left,right」等があり、それぞれボックスの下辺、左辺、右辺を意味します。 例えば「スクロールしてh1要素が完全に画面から上になくなるとイベントを起こしたい」等の時は、 「bottom」を使用するといいと言うことですね。 7、「fixedJudge(「globalN」上辺のブラウザ上での高さ位置)」が0以下(画面上部よりさらに上に行き、見えない状態)の場合という条件式を記述。 8、「DOM要素.classList.add('クラス名');」とすることで、取得したDOM要素に、CSSで使用できるクラス名(HTMLでの「class=""」と同じ)を追加できます。今回の記述だと、ID名「headerFixed」の要素に「fixed」というクラスを付与する、と言う意味になります。 記述コードに関しての説明は以上になりますが、このコードだと一度付与されたクラスはずっと付与された状態のままで、 画像の様な状態になってしまいます。 そこで「fixedJudge」が0より上(画面上部より下に行き、見える状態)になると付与したクラスを削除したいと思います。 クラス付与が「classList.add」なのに対し、クラス削除は「classList.remove」で行えます。 ここでよく間違いがちなのが付与を追加したとき同様に「グローバルナビ」要素に「remove」メソッドを適用してしまうことです。 「グローバルナビ」が上部固定された状態だと、どれだけスクロールしたとしても座標が「0」から変わることはあり得ません。なので、 JSコード window.addEventListener('load',fixedCheck); window.addEventListener('resize',fixedCheck); window.addEventListener('scroll',fixedCheck,{passive:true}); function fixedCheck(){ let h1Bottom=document.getElementById('headerH1'); //変更点1 let globalN=document.getElementById('headerFixed'); let fixedJudge=h1Bottom.getBoundingClientRect().bottom; //変更点2 if(fixedJudge<=0){ globalN.classList.add('fixed'); }else{ //変更点3 globalN.classList.remove('fixed'); //変更点4 } } 変更点1、HTMLのヘッダー内にある「h1」を取得し変数「h1Bottom」に代入し、 変更点2、次に「getBoundingClientRect().bottom」で「h1Bottom」要素の下辺を基準とする、ブラウザ上の高さ位置を取得し、「fixedJudge」変数へ代入。(この時点で「if文」条件式の基準となる座標が「グローバルナビの上辺」から「h1要素の下辺」に変わっています。) 変更点3、if文条件式以外の場合の「else」を追加。 変更点4、「globalN」から「fixed」クラスを削除する文を記述。 この様に記述することで、 h1要素の下辺がビューポート上辺より上(h1要素が見えない状態)にある時は、「globalN」に「fixed」クラスを付与し、 ビューポート上辺より下(h1要素が見える状態)の時は「globalN」から「fixed」クラスを削除する、 と言う記述の意味になりました。 ↓↓↓↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓↓↓↓ 実際にブラウザに表示してみるとこのようになりましたね。 これでナビが画面上部に固定されついてくる方法の説明は以上になります。 ご購読ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Web Serial API を利用した p5.js用の p5.web-serial というライブラリを試す(p5.js Web Editor で使う)

今まで見かけていた「p5.js でシリアル通信を使うライブラリ」というと、公式ページで紹介されている「p5-serial/p5.serialport」があったのですが、それとは別の最近リリースされたっぽいものを見かけました。 そこで、その新しいライブラリを p5.js Web Editor上で試してみた、というのがこの記事の内容です。 ongzzzzzz/p5.web-serial の仕組みについて 今回試してみるのは「ongzzzzzz/p5.web-serial」というライブラリです。 上記の「p5-serial/p5.serialport」との違いは、Webページ上でシリアル通信を実現する方法です。 「p5-serial/p5.serialport」のほうは、「p5.serialcontrol application または p5.serialserver」という仲介役となるアプリケーションを動かしつつ、それと別に p5.js のプログラムを動かす構成になるようです。 一方、「ongzzzzzz/p5.web-serial」のほうは、ブラウザの Web Serial API を用いているため、仲介役になるアプリを別に用意することなくシリアル通信を行えます。ただし、Web Serial API をサポートしているブラウザは限定的(基本的に Chrome系のみ)であるため、その点は注意が必要です。 【余談】 Web Serial APIについて 余談ですが、Web Serial API を利用した通信について、過去にいくつか記事を書いているので、Web Serial API が気になるという方は、よろしければご覧ください。 過去に書いた記事 Web Serial API を使って micro:bit からセンサーの値(XYZ)を読み取る&リアルタイムなグラフ化 Web Serial API を使って micro:bit からセンサーの値を読み取る(途中段階まで) Web Serial API を使った micro:bit への値の書き込み Web Serial API を最短の手順で試したくてやったこと(micro:bit を利用) ongzzzzzz/p5.web-serial を使ってみる それでは、p5.js Web Editor上で ongzzzzzz/p5.web-serial を使ってみます。 ブラウザは Google Chrome を利用します。 簡単な動作確認まで行う まずは、index.html に以下の行を追加します(※ 公式の GitHubリポジトリで紹介されているリンクです)。 <script src="https://cdn.jsdelivr.net/gh/ongzzzzzz/p5.web-serial/lib/p5.web-serial.js"></script> そして、script.js のほうで公式のサンプルを動かしてみます。 // additional code here... と書かれた部分は何も修正せずという状態で、動作確認だけを行います。 let port, reader, writer; async function setup() { createCanvas(400, 400); // additional code here... noLoop(); ({ port, reader, writer } = await getPort()); loop(); } function draw() { background(220); } 上記のプログラムを実行すると、プレビュー画面のほうに以下の表示が行われます。 そして、表示された2つのボタンのうちの左側のものを押すと、以下のように Web Serial API の利用許可を求めるダイアログが表示されました。 ここでシリアル通信に使いたいシリアルポートを選択する操作を本来は行うのですが、今時点ではシリアル通信をさせたいデバイスをつないでないので、表示が出ることだけ確認しておきます。 デバイスとの通信を行ってみる(ブラウザからの書き込み) Sending data from the browser to the Arduino という部分を見つつ、ブラウザからの書き込みを試してみます。 p5.js側のプログラム ちなみに、公式ページには以下の例が書かれています。 async function draw() { if (port) { try { if (mouseIsPressed) { // do something... await writer.write("clicked!\n"); } else { // do something... await writer.write("not clicked!\n"); } } catch (e) { console.error(e) } } } こちらは、デバイスとの間でのシリアル通信できる状態で、マウスのボタンを押しているかどうかによって、異なる文字列を書きこむもののようです。 先ほど動作確認を行ったプログラムに混ぜ込みつつ、少し変更を加えて動かしてみます。 まず、sketch.js は以下にしました。 let port, reader, writer; async function setup() { createCanvas(400, 400); noLoop(); ({ port, reader, writer } = await getPort()); loop(); frameRate(4); } async function draw() { if (port) { try { if (mouseIsPressed) { background("BLUE"); await writer.write("AAA\n"); } else { background("BLACK"); } } catch (e) { console.error(e); } } } micro:bit側のプログラム あとはデバイス側の準備です。 p5.web-serial/examples/web-to-arduino/main.ino に Arduino用のサンプルプログラムが掲載されていますが、自分は過去に Web Serial API のお試しに使った micro:bit を使います。 micro:bit用のプログラムは、以下の内容のものを MakeCode で作りました。 それでは micro:bit へプログラムを書きこんで準備ができたら、micro:bit と PC を USB で接続し、その後にブラウザから micro:bit への書き込みを試します。 実際の動作の様子 プログラムを書き込み済みの micro:bit と PC を USB で接続した状態で、p5.js のプログラムを実行します。 プレビュー画面に表示される以下の画面で、「Add a device」と書かれたボタンを押し、その後に表示されるダイアログ上に micro:bit という名前を含むものがあると思いますので、それを選んでください。 そして、「Connect!」と書かれたほうのボタンを押します。 そうすると、プレビュー画面が以下のような表示になるので、プレビュー画面上をマウスでクリックしてください。マウスをクリックしてない時は黒背景で、クリックをした時に青背景になると思います。 そして、クリックをした時には micro:bit側で、以下の動画にあるような変化が起こると思います。 【ツイートを後で追加】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Web Serial API を利用できる p5.js用のライブラリ「p5.web-serial」で micro:bit とのシリアル通信(p5.js Web Editor・MakeCodeを利用)

今まで見かけていた「p5.js でシリアル通信を使うライブラリ」というと、公式ページで紹介されている「p5-serial/p5.serialport」があったのですが、それとは別の最近リリースされたっぽいライブラリを見かけました。 そこで、その新しいライブラリを p5.js Web Editor上で試してみた、というのがこの記事の内容です。 ongzzzzzz/p5.web-serial の仕組みについて 今回試してみるのは「ongzzzzzz/p5.web-serial」というライブラリです。 上記の「p5-serial/p5.serialport」との違いは、Webページ上でシリアル通信を実現する方法です。 「p5-serial/p5.serialport」のほうは、「p5.serialcontrol application または p5.serialserver」という仲介役となるアプリを動かしつつ、それと別に p5.js のプログラムを動かす構成になるようです。 一方、「ongzzzzzz/p5.web-serial」のほうはブラウザの Web Serial API を用いており、そのような仲介役になるアプリを別に用意することなくシリアル通信を行えます。ただし、Web Serial API をサポートしているブラウザは限定的(基本的に Chrome系のみ)であるため、その点は注意が必要です。 【余談】 Web Serial APIについて 余談ですが、Web Serial API を利用した通信について、過去にいくつか記事を書いているので、Web Serial API が気になるという方は、よろしければご覧ください。 過去に書いた記事 Web Serial API を使って micro:bit からセンサーの値(XYZ)を読み取る&リアルタイムなグラフ化 Web Serial API を使って micro:bit からセンサーの値を読み取る(途中段階まで) Web Serial API を使った micro:bit への値の書き込み Web Serial API を最短の手順で試したくてやったこと(micro:bit を利用) ongzzzzzz/p5.web-serial を使ってみる それでは、p5.js Web Editor上で ongzzzzzz/p5.web-serial を使ってみます(ブラウザは Google Chrome を利用します)。 簡単な動作確認まで行う まずは、index.html に以下の行を追加します(※ 公式の GitHubリポジトリで紹介されているリンクです)。 <script src="https://cdn.jsdelivr.net/gh/ongzzzzzz/p5.web-serial/lib/p5.web-serial.js"></script> そして、script.js のほうで公式のサンプルを動かしてみます。 // additional code here... と書かれた部分は何も修正せずという状態で、動作確認だけを行います。 let port, reader, writer; async function setup() { createCanvas(400, 400); // additional code here... noLoop(); ({ port, reader, writer } = await getPort()); loop(); } function draw() { background(220); } 上記のプログラムを実行すると、プレビュー画面のほうに以下の表示が行われます。 そして、表示された2つのボタンのうちの左側のものを押すと、以下のように Web Serial API の利用許可を求めるダイアログが表示されました。 ここで本来は、シリアル通信に使いたいシリアルポートを選択する操作を行うのですが、今時点ではシリアル通信をさせたいデバイスをつないでないので、表示が出ることだけ確認しておきます。 デバイスとの通信を行ってみる(ブラウザからの書き込み) Sending data from the browser to the Arduino という部分を見つつ、ブラウザからの書き込みを試してみます。 p5.js側のプログラム ちなみに、公式ページには以下の例が書かれています。 async function draw() { if (port) { try { if (mouseIsPressed) { // do something... await writer.write("clicked!\n"); } else { // do something... await writer.write("not clicked!\n"); } } catch (e) { console.error(e) } } } こちらは、デバイスとの間でのシリアル通信できる状態で、マウスのボタンを押しているかどうかによって、異なる文字列を書きこむもののようです。 先ほど動作確認を行ったプログラムに混ぜ込みつつ、少し変更を加えて動かしてみます。 まず、sketch.js は以下にしました。 let port, reader, writer; async function setup() { createCanvas(400, 400); noLoop(); ({ port, reader, writer } = await getPort()); loop(); frameRate(4); } async function draw() { if (port) { try { if (mouseIsPressed) { background("BLUE"); await writer.write("AAA\n"); } else { background("BLACK"); } } catch (e) { console.error(e); } } } micro:bit側のプログラム あとはデバイス側の準備です。 p5.web-serial/examples/web-to-arduino/main.ino に Arduino用のサンプルプログラムが掲載されていますが、自分は過去の Web Serial API のお試しで使った micro:bit を使います。 micro:bit用のプログラムは、以下の内容のものを MakeCode で作りました。 それでは micro:bit へプログラムを書きこみましょう。 実際の動作の様子 プログラムを書き込み済みの micro:bit と PC を USB で接続した状態で、p5.js のプログラムを実行します。 プレビュー画面に表示される以下の画面で、「Add a device」と書かれたボタンを押し、その後に表示されるダイアログ上に micro:bit という名前を含むものがあると思いますので、それを選んでください。 そして、「Connect!」と書かれたほうのボタンを押します。 そうすると、プレビュー画面が以下のような表示になるので、プレビュー画面上をマウスでクリックしてください。マウスをクリックしてない時は黒背景で、クリックをした時に青背景になると思います。 そして、クリックをした時には micro:bit側で、以下の動画にあるような LED表示の変化が起こると思います。 #p5js のプログラムと #microbit との Web Serial API を使ったシリアル通信!(mouseIsPressed に反応する形)↑記事も書いた●Web Serial API を利用できる p5.js用のライブラリ「p5.web-serial」で micro:bit とのシリアル通信(p5.js Web Editor・MakeCodeを利用) https://t.co/3vsdSUi5xV pic.twitter.com/i7hymLvFDV— you (@youtoy) April 2, 2022 無事、意図通りに動いたことを確認できました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBootの値をJavaScriptに渡す方法

はじめに SpringBootで設定した値をJavaScriptに渡す際に、少しばかり、つまずいたため備忘録がてら記録しておこうと思います。 SpringBootとJavaScriptを用いた場合には、非常にあるあるな事象だと思うので、ご参考になれば幸いです。 ちなみに、Thymeleafでは、このことを「 JavaScriptナチュラルテンプレート 」と呼ぶようです。 ControllerからJavaScriptに値を渡す方法 以下のようにModelに登録してある値をJavaScriptに渡したいとします。 SampleController.java @GetMapping("/index") public String getIndex(EasyHouseholdForm form, Model model) { model.addAttribute("form", form); return "sample/index"; } これを渡す方法はThymeleafで以下のようにします。 index.html <script th:inline="javascript"> const form = /*[[${form}]]*/"form"; console.log(form); </script> ポイントとしては、<script>タグのth:inline属性の値にjavascriptを設定し、/*[[${渡したい値}]]*/とすることでJavaからJavaScriptに値を渡すことができます。 また、定数定義の後ろの "form"; ですが、こちらは無視される仕様となっているようです。 これを加えないとエラーとなり、連続しての定数もしくは変数の定義(以下、参照)ができないようです。 index.html <script th:inline="javascript"> const hoge = /*[[${hoge}]]*/"hoge"; const fuga = /*[[${fuga}]]*/"fuga"; console.log(form); </script> 上記のように「JavaScriptナチュラルテンプレート」の記載をすれば、連続して定数・変数の定義が可能です。 もちろん、JavaScriptの外部ファイル(〇〇.js)に渡したい場合も同様の内容で実装することができます。 ※もちろん、HTML内で該当のjsファイルを読み込んでいないとできませんが・・・ JSファイルに値を渡す方法 こちらも最初のやり方は同じです。 index.html <script th:inline="javascript"> const color = /*[[${form}]]*/"form"; // JavaScriptの関数呼び出し sample(); </script> まずはHTMLで値を変数に代入します。 あとはこの値を使用したいJavaScriptファイルで使用するだけです。 index.js 'use strict' { function sample(){ console.log(form); } } このようにすれば、JavaScriptファイルでもJavaの値を使用することができます。 ただし、この方法には制約があるので、その点だけ注意が必要です。 以下が、その制約です。 <script>タグにsrc属性、またはth:src属性が指定してある場合には使用できないこと(th:inline属性とsrc属性ないしth:src属性の併用は不可) 上記の制約の通り、<head>タグ内で<script>タグを作成の上、そこでsrc属性、ないしth:src属性を利用して、JavaScriptファイルを読み込む必要がある とはいえ、各自の仕様や好みにもよるので、前者を使用する人が大多数かと思います。 筆者自身の場合は、HTML内でのJavaScriptの記述は最低限にして、JSファイルでJavaScriptを書く場合が多いので、後者の方法が必須となります。 このように、好みによるところもあるので前者を使うのが多くの人にとっては無難かと思われます。 参考文献 Thymeleaf Spring Bootの設定値をJavaScriptの引数に渡してみた SpringBoot thymeleafでデータをjs内で受け取る
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

いいね Ajaxにする

Ajaxとは? ページを更新することなくページの内容だけを入れ替えられる。 ajaxの中核を支えているのはJavacriptの技術。 デメリットもあるらしいがそれを差し引いてもメリットがあると今は理解した。 何から手を出していいのかわからない。 早速実践 ボタン my_app/app/views/favorites/_favorite.html.erb <% if current_user.like?(micropost) %> <%= button_to user_favorite_path(current_user, micropost), method: :delete remote: :true do %> <%= micropost.liked.count %> <span style = "color:red;">♡</span> <% end %> <% else %> <%= button_to user_favorites_path(current_user, micropost), method: :post remote: :true do %> <%= micropost.liked.count %> <span >♡</span> <% end %> <% end %> :remote :trueでAjaxでリンクを処理ができるらしい。 コントローラ my_app/app/controllers/favorite/favorites_controller.rb class FavoritesController < ApplicationController before_action :logged_in_user, only: [:create, :destroy] def create @micropost = Micropost.find_by(id: params[:format]) current_user.like(@micropost) respond_to do |format| format.html { redirect_to request.referer } format.js { redirect_to request.referer } end end def destroy @micropost = Micropost.find_by(id: params[:id]) current_user.unlike(@micropost) respond_to do |format| format.html { redirect_to request.referer } format.js end end end MVCのことを考えながら見てみると、 ボタン(オプション引数を使って)でコンローラに行ってビューに表示させる。 それにあっているのかな? JavaScriptが有効になっていても、まだ十分に対応できていない部分があります。 というのも、Ajaxリクエストを受信した場合は、 Railsが自動的にアクションと同じ名前を持つJavaScript用の埋め込みRuby(.js.erb)ファイル(create.js.erbやdestroy.js.erbなど)を呼び出すからです。 ユーザーをフォローしたときやフォロー解除したときにプロフィールページを更新するために、 私たちがこれから作成および編集しなければならないのは、まさにこれらのファイルです。 予想 ファイルを小分けにする理由はリアクションを早くするためなのかもしれない。 jqueryを使う CSS idで指定する ドル記号($)とCSS idを使って、DOM要素にアクセスする文法について知る必要があります。 例えばfollow_formの要素をjQueryで操作するには、次のようにアクセスします。 $("#follow_form") jQueryの文法はCSSの記法から影響を受けており、#シンボルを使ってCSSのidを指定します。 HTMLに表示させる 指定された要素の内側にあるHTMLを、引数の内容で更新します。 例えばフォロー用フォーム全体を"foobar"という文字列で置き換えたい場合は、 次のようなコードになります。 $("#follow_form").html("foobar") create.js.erbファイルでは、フォロー用のフォームをunfollowパーシャルで更新し、 フォロワーのカウントを更新するのにERbを使っています 予想 できるだけ小さいファイルにする方がいいのかな? ビュー app/views/microposts/_micropost.html.erb <li id="micropost-<%= micropost.id %>"> . . . <%= render 'microposts/favorite', micropost: micropost %> . . . </li> app/views/microposts/_favorite.html.erb <div id="like_form"> <% if current_user.like?(micropost) %> <%= render "microposts/unlike", micropost: micropost %> <% else %> <%= render "microposts/like", micropost: micropost %> <% end %> </div> app/views/microposts/_unlike.html.erb <%= button_to user_favorite_path(current_user, micropost), method: :delete ,remote: true do %> <%= micropost.liked.count %> <span style = "color:red;">♡</span> <% end %> app/views/microposts/_like.html.erb <%= button_to user_favorites_path(current_user, micropost), method: :post, remote: true do %> <%= micropost.liked.count %> <span >♡</span> <% end %> エラー ActionController::UnknownFormat app/views/favorites/create.js.erb $("#like_form").html("<%= escape_javascript(render 'microposts/like', micropost: @micropost) %>"); app/views/favorites/destroy.js.erb $("#like_form").html("<%= escape_javascript(render 'microposts/unlike', micropost: @micropost) %>"); できなかった。 current_user.like?(miropost)でcurrent_userがうまく機能しないらしい。 これからまた勉強し直して必ず身を結べるように努力する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

マンハッタン距離について

勉強中のメモ書きです。 マンハッタン距離とは 2つの座標の差の総和を表したもの。2点間の距離。 |x_1 - x_2| + |y_1 - y_2| で表せる。 例えば下記の図のような座標があったとする。 (画像は 「高校数学の美しい物語」さんより引用) (x2, y3) と (x5,y7) の2点間のマンハッタン距離は |2-5| + |3-7| = 7 で、7となる。 マンハッタン距離の名称は、碁盤のように道路が張り巡らさせれているマンハッタンから由来、2点間を徒歩で歩いたらどれぐらいの距離がかかるか、を示したもの(らしい)。 JavaScript でマンハッタン距離を計算する 以下、標準入力で「地点数」「各地点のx、y座標情報」が、標準入力で提供されているとする。 1行目に、地点の数 「n」。 2行目以降に地点情報が記述。 x, y を空白区切りで表し、2点を2行にわたって記述されている。 入力例: 2 2 3 5 7 以下のコードでマンハッタン距離の算出ができる function main(input) { const args = input.split("\n"); const n = parseInt(args[0], 10); let x = []; let y = []; for(i = 0 ; i < n ; i++) { let nums = args[i+1].split(' '); x.push(parseInt(nums[0], 10)); y.push(parseInt(nums[1], 10)); } const manhattan = Math.abs(x[0] - x[1]) + Math.abs(y[0] - y[1]); console.log(manhattan) // 7 } main(require("fs").readFileSync("/dev/stdin", "utf8")); 地点情報が2行以上にわたる場合、行数分を配列x、yに格納してそれぞれの地点間の距離を求める。 参考 L1距離(マンハッタン距離)の意味と性質 https://manabitimes.jp/math/1127 マンハッタン距離 https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%B3%E3%83%8F%E3%83%83%E3%82%BF%E3%83%B3%E8%B7%9D%E9%9B%A2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【コピペで動く】Reactで超簡単にルーレットを作る方法

前書き 以前、個人アプリを開発した際にルーレット作ることがあったので今回は次回使う時用のメモとルーレットを作りたい人へのコード共有を兼ねて記事を作成します! setIntervalを使えばできそうだなぁと思って実装したら副作用のせいでうまくできなかったのを覚えています。。笑 JavaScriptではルーレットを作れるけど、Reactでは副作用のせいでうまくできない。。! という僕と同じ状況の方がいましたら是非ご覧ください 実装イメージは以下の通りです。 注意点 今回のコードはルーレットを動かす記述しか書いてありません。 そのため、実装イメージのようなスタイリングやアニメーションの記述は省かれております。 スタイリングやアニメーションは人によって異なると思いますので適宜お好みであててください。 コード import { useState, useEffect, useCallback, memo } from "react"; export const Roulette = memo(() => { const [start, setStart] = useState(false); const [index, setIndex] = useState(0); const rouletteContents = [ "カレー", "パスタ", "唐揚げ", "天ぷら", "中華", "ハンバーグ", "うどん", "肉じゃが" ]; //ボタンの文言を変更する処理 const startRoulette = useCallback(() => { setStart(!start); }, [start]); //ルーレットを回す処理 useEffect(() => { if (start) { const interval = setInterval(() => { setIndex((oldIndex) => { if (oldIndex < rouletteContents.length - 1) return oldIndex + 1; return 0; }); }, 50);//ルーレットの中身を切り替える速度 return () => clearInterval(interval); } else if (!start) { return () => clearInterval(); } }, [start]); return ( <> <div> <p>今日のメニューは・・・</p> <p>{rouletteContents[index]}</p> </div> <button type="button" onClick={startRoulette}> {start ? "ストップ" : "スタート"} </button> </> ); }); 最後に 参考になりましたでしょうか? この他にもQiitaやTwitterでは文系大学生の僕がプログラミングについて発信してますのでフォローしていただけると嬉しいです! おすすめ記事 【2022年版】駆け出しフロントエンドエンジニアが覚えたい用語一言メモ集 【React】本番環境にデプロイして画面が真っ白になった時の解決方法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Vue]元教師が教師の業務効率化のためにランダム指名アプリを作りました

サービス紹介 座席数を指定して、生徒を指名できる、シンプルなアプリです。 使い方 座席数を指定して、後は指名ボタンを押すだけ! きっかけ きっかけは自分自身が生徒だった時に、授業を受けている際に「あれ、なんか前の席の人ばっかり当てられてるな〜」と感じたことから始まりました。 そして、実際に2年ほど教師をしていたのですが、前の席の人はやはり当てやすいのです。 出典 https://www.paylessimages.jp/detail.php?id=gf1420736473 一回一回の授業ではそこまで差は出ませんが、一年も続けると席が固定の場合、とても不公平になるかと思いました。 そこで、生徒をランダムに指名してくれるアプリを作りました! このアプリを使えば不公平がないかつ、誰が当たるかわからない緊張感もある、楽しい授業がしやすいかなと感じます。 使用技術 vue.js(2.0) Firebase Vuetify ハマったところ Vueのコンポーネント志向を活用しようと、トップページと、列と、一つ一つのセルという三つのコンポーネントを作成しました。 HelloWorld.vue <v-row class="row py-0 px-0" v-for="i in changeHeight" :key="i" color="blue darken-2"> <Row :mathWidth="mathWidth" :rowId="i" :propRandomId="propRandomId"/> </v-row> Row.vue <v-col class="pa-0" justify="center" v-for="i in changeWidth" :key="i" > <Cell :id="rowId + '_' + i" :ref="rowId+'_'+i"> </Cell> </v-col> 縦横の席数を受け渡して全体を表示しています。 こちらの受け渡しはpropsを使用しているのですが、うまく受け渡せなかったり、予期せぬ挙動が生まれたりと、そこそこ大変でした。 storeを使うべきか、propsで良いのかという判断がなかなか難しいです。 また、ランダムに指定した席ひとつだけ赤くするという処理も、一つ一つのCellに 1_1 1_2 1_3 2_1 2_2 2_3 とインデックスを付ける処理ですが、 Row.vue watch: { propRandomId: function () { for(let i = 0; i < this.mathWidth; i++){ this.$refs[this.rowId+"_"+(i+1)][0].$el.children[0].style.backgroundColor="lightgray"; } if(!this.$refs[this.propRandomId]){ return } this.$refs[this.propRandomId][0].$el.children[0].style.backgroundColor="red"; }, }, $refsを使ってかなりむりやりやっています。 もっとスマートにかけたらよりいいのかなーとか思ったりします。 今後の改良点 もし反響が大きければ より素敵なアニメーションの実装 席に生徒名を設定できる機能 一度当たった人は除外して再抽選 あたりの機能は実装したいなと考えています。 LGTMやツイートの拡散などしていただけると本当にありがたいです、、、 おまけ Twitterで一緒に個人開発してくれる人、一緒にプログラミングを勉強してくれる人を募集しています! 結構発信しているので、是非ともフォローをお願いいたします。 また、開発を手厚くサポートしてくれたメンターさんには本当に頭が上がりません、。 ありがとうございました。 サービス 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでlink_to deleteが出来ない

某オンラインスクールで学習4ヶ月目、 Railsにてオリジナルwebアプリを作成していて link_toの"削除"が実行できなくてぐるぐるしたので備忘録として。   dpテーブルに投稿したレコードを削除するため実装、削除出来ず。 <%= link_to "報告の削除", dp_path(@dp.id), method: :delete %>   エラー画面も出ず、元の画面に戻ってきてしまう。 ログを見るとどうやらGETで動いている模様。   参考にした記事 https://qiita.com/mami3sansan/items/6a9710b3ffdc937aa5f3 https://nabelog.org/695/ https://takayuki-inoue.hatenablog.com/entry/2018/01/12/105846   その他いくつか読んでみたが、解決に至る糸口が見つからず。 上記記事等から得た知識を元に思い当たる節を探ってみたところ、 作成初期に放り込んでいた、bootstrap絡みの cssやらjavascriptあたりに要因がありそうな気配が。 (bootstrapは全然使いこなせず放置しておりました) で、その中のjavascriptが要因だった模様。 該当と思しきファイルをエイっと削除(これもイケナイような気もする)したところ、 無事にアプリ内のデータ削除が実行出来るようになりました。 訳も分からないまま適当に放り込まない、 ということを念頭に地道に勉強続けます。。。 ※ここの理解が違いますよ、等など教えていただけましたら有り難いです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む