- 投稿日:2022-01-12T22:28:30+09:00
ワイ「Node.jsってなんぞや?」
ワイ「JavaScriptを触りたいンゴ」 ワイ「せっかくJavaScriptとTypeScriptについて知ったから触ってみたいで」 PC「JavaScriptはブラウザ上で動く言語やで^^」 ワイ「なんやこいつ」 ワイ「C++とかPythonとかとは仕様が違うんか」 PC「せや」 PC「だからファイルの読み書きが出来なかったり、通信が出来なかったりするんやで^^」 ワイ「なんやこいつ」 ワイ「どうするのが正解なんや?」 ワイ「まあ誰かがいい感じの作ってくれてるやろ(未来予知)」 PC「Node.jsを使えばいいんやで」 ワイ「ほらな」 ワイ「なんやそいつは」 Nodeくん「説明しよう!!」 ワイ「なんやこいつは」 Nodeくん「Node.jsは一言で言うと、JavaScriptの実行環境だよ」 Nodeくん「ローカルで実行するからファイルの読み書きや、通信が出来るようになるんだ」 ワイ「やっぱり先人サマサマやで^^」 ワイ「npmってなんや?」 ワイ「早速Node.jsをインストールしたで インストーラーから簡単に入れれて便利な時代になったもんや^^」 ワイ「でも記事とかでよく見るnpmってなにモンなんや??」 Nodeくん「npmはパッケージを管理するツールだね」 Nodeくん「だからnpmはpipやaptみたいなもんだね」 ワイ「ということはライブラリをこっからインストール出来るんか?」 Nodeくん「exactly!!」 Nodeくん「だからJavaScriptのソースをDLして<script>でincludeしなくていいんだ!」 ワイ「はえ~ 便利やな~」 ワイ「npmで何が入れれるんや?」 ワイ「npmがpip的なのは分かったけど有名どころさんは何があるんや?」 Nodeくん「有名どころで言うと、フレームワークにExpress.jsや、JavaScriptのフレームワークにVue.jsがあるよ」 ワイ「初めて聞いたな」 Nodeくん「Express.jsは一番有名なライブラリで、APIの実装とかNode.jsでの開発を爆速にしてくれるんだ」 ワイ「なるほどな?」 Nodeくん「主にWebアプリケーションの開発に向いてるね」 Nodeくん「Vue.jsも大人気JavaScriptフレームワークだよ」 ワイ「こっちはちょっと聞いたことあるぞ」 Nodeくん「Vue.jsについて」 Nodeくん「Vue.jsはhtmlを動的に制御できるフレームワークみたいな感じかな」 ワイ「ほう」 Nodeくん「hoge.vueファイル形式で記述していって、<template>、<script>、<style>を同一ファイルに入れれるんだ」 ワイ「便利やなぁ」 Nodeくん「それだけじゃなくてhtmlのタグにifやforを入れれたりもするんだ!!」 ワイ「想像以上に便利だな」 ワイ「たくさん知れたわ」 ワイ「ワイのNode.js人生の始まりや!」 自分が作成したVueプログラム bv-https://github.com/Kazuryu0907/bv vue-bootstrapを使用 これは高専の課題で作成された記事です 最後まで読んでいただきありがとうございました。 参考文献 ゼロからはじめるExpress + Node.jsを使ったアプリ開発 【必ず知っておきたい】おすすめNode.jsフレームワーク ワイ「いうても型なんて面倒くさいだけやろ?」(Qiita)
- 投稿日:2022-01-12T19:28:04+09:00
VSCodeのPrettier+black環境の作り方
Formatterとは コードの種類に応じて、自動で空白とか改行などの整形を行う拡張機能のこと。 有名なものでは、Prettier(JS, TS, yaml, html等が対応)やBlack(python用)などがある。 基本的にはPrettierを用いれば、大抵のプログラムは対応しているが、 PrettierはPythonに非対応のため、Pythonの時のみBlackを使うように設定する必要がある。 Prettierのインストール VSCodeでPrettierを使用するには、拡張機能をインストールします。 まずVS CodeのExtension panelでPrettier-Code Formatterを検索しインストールします。 default formatterをPrettierに設定 画面左上のタブからCode→基本設定→設定を開き、 editor.defaultFormatterと検索して、Prettier-Code Formatterを選択 これでdefault formatterをPrettierに変更することができた。 次にeditor.formatOnSaveと検索してこれをTrueに変える。(ファイル保存時にFormatterを適用する設定) Blackのインストール 下記コマンドでBlackをインストールする。 pip3 install black 次に画面左上のタブからCode→基本設定→設定を開き、 python.formatting.providerと検索して、blackを選択 しかしこのままだと、Pythonであろうとdefault formatterであるPrettierが適用されてしまい、エラーが出る。 このため、pythonコードの場合のみ、prettierではなくblackを適用するよう下記の設定を追加する必要がある。 python時のみdefault formatterを適用しない設定の追加 画面左上のタブからCode→基本設定→設定を開き、右上の3つのアイコンの一番左のものを押して、settings.jsonを開く。 そこで、一番下に "[python]": { "editor.defaultFormatter": null, }, というPythonの時のみ動作する例外設定を追加する。 最終的にsettings.jsonが以下のようになっていることを確認する。 settings.json { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "python.formatting.provider": "black", "[python]": { "editor.defaultFormatter": null, }, } formatterの動作確認 pythonファイルのフォーマット(black) 下記のようなフォーマットが壊れたpythonファイルを作成して、保存するとちゃんと整形されることを確認する。 test.py(整形前) a = [ 1, 2, 3] test.py(整形後) a = [1, 2, 3] その他ファイルのフォーマット(prettier) 下記のようなフォーマットが壊れたjsファイルを作成して、保存するとちゃんと整形されることを確認する。 test.js(整形前) const test = 3; const func =() => { return 0; }; test.js(整形後) const test = 3; const func = () => { return 0; };
- 投稿日:2022-01-12T17:37:00+09:00
twitterAPI を利用するなら json-bigintは使わない方が良い
大きい数字を扱うために、json-bigintを使おう。 って記事をよく見る const JSONbig = require('json-bigint'); axios.defaults.transformResponse = function (data) { return JSONbig.parse(data); }; 何桁まで使えるか?ってことは書いてない。 そこで調べてみた。 json-bigint あり 送信 最大16桁 ※big-intが効いてない可能性もあり 受信 最大19桁 1480959136104054785 json-bigint なし 送信 最大16桁 5333330289473823 受信 最大16桁 1480959136104054 上記を踏まえて、 2022年1月12日現在、twitter_idの最大は何桁なのか?というと 最大19桁 1480959136104054785 であった。 さらに桁は増え続けるので、twitter_apiなどを利用する場合は 明示的にtwitter_idなどのidを文字列として変換して送受信する必要がある。 また api からは id ではなく id_str を利用するようにしよう。
- 投稿日:2022-01-12T14:55:51+09:00
Yellowfinで睡眠情報の帯グラフを作成する
はじめに 今回も要望がありd3.jsのライブラリや記事を探していたら、近いことをされている方がいたのでその方の記事のX軸とY軸を切り替えたものを今回記事にしました。 睡眠時間のデータを時間ごとの帯グラフの上に描画するイメージです。 ソースはこちら 詳しくはその方の記事の解説を見てもらえるとわかりますが、このグラフは直近7日分の日付を動的に取得しているので場合によって静的にするか-1日だけの表示にするか変更が必要です。また、データの分割は同じ方のこの記事が参考になります。 オリジナル版との違いはXY軸の変換とデータの配列の3つめに種類を与えることで色分けを可能にしているところです。 Yellowfinのレポートの値を使うとしたらこの記事が参考になると思います。このソースの場合はdoDrawingの中のdata変数にデータが入っています。 time.js //generateChart は必須の関数であり、Javascriptグラフの作成において呼び出しされます generateChart = function (options) { // これはお使いのブラウザのデバッガのブレークポイントのトリガとなるため、Javascriptをデバッグすることができます debugger; // グラフを描画する部分です var $chartDrawDiv = $(options.divSelector); // Javascriptに関係なく任意のポートレットでスクロールバーを停止するには、このCSSクラスを使用します $chartDrawDiv.addClass('jsChartNoOverflow'); // これにより、datasetから高さと幅が取得されます。グラフの作成時にこれらを使用して、 // ダッシュボード、カンバス、ストーリーボードに正しく合わせます //var height = options.dataset.chart_information.height; //var width = options.dataset.chart_information.width; var height = 400; var width = 800; // 必要に応じて、RAWデータJSONをグラフに必要な形式に変換します。 var processedData = processData(options.dataset.data); // グラフの実績の描画を $chartDiv に行います。 doDrawing(processedData, $chartDrawDiv, height, width, options.errorCallback); }, processData = function (dataset) { // データが格納されるdatasetはカラム(列)ベースの形式であり、各カラム(列)にはデータの配列が含まれます // eg. dataset.column_name[0].raw_data, dataset.column_name[0].formatted_data }, doDrawing = function (data, $chartDiv, height, width, errorFunction) { // require を使用して必要なJavascriptライブラリを読み込みます // 付属するライブラリとその場所: // js/chartingLibraries/c3/c3 // js/chartingLibraries/chartjs/Chart // js/chartingLibraries/d3_3.5.17/d3_3.5.17 require(['js/chartingLibraries/d3/d3'], function (d3) { try { let divided = [ [ new Date("2022-01-10 03:00:00"), new Date("2022-01-10 05:00:00"), 10 ], [ new Date("2022-01-10 05:30:00"), new Date("2022-01-10 07:00:00"), 11 ], [ new Date("2022-01-11 01:00:00"), new Date("2022-01-11 05:00:00"), 12 ] ]; var $canvas = $('<svg id="svg"></svg>'); $chartDiv.append($canvas); var margin = { left: 30, right: 30, bottom: 50, top: 30, }; let svg = d3.select("#svg") .attr("width", width) .attr("height", height); // グラフ描画コードはこちら /* y 方向のスケールを作成する */ let nDates = 7; // 一週間分のデータを表示する let y = d3.scaleLinear() .domain([0, nDates]) .range([margin.top, height - margin.bottom]); /* x 方向のスケールを作成する */ let x = d3.scaleLinear() .domain([0, 24]) // 00:00:00 ~ 24:00:00 .range([margin.left, width - margin.right]); /* 日付文字列のリストを取得する */ let tod = new Date(); let dateStrings = []; let tmpDate = null; for (let i = 0; i < nDates; i++) { tmpDate = new Date(); tmpDate.setDate(tod.getDate() - i); let ymd = tmpDate.toLocaleString().split(" ")[0]; let md = ymd.substring(5); // 年を取り除く dateStrings.push(md); } dateStrings.reverse(); /* x 軸と目盛りを作成する */ let xAxis = svg.append("g") .attr("class", "x_axis") .attr( "transform", "translate(" + [ 0, height - margin.bottom ].join(",") + ")" ) .call( d3.axisBottom(x) .ticks(24) .tickSize(-height + margin.top + margin.bottom) .tickFormat(function (d) { return d + ":00"; }) ); /* y 軸と目盛りを作成する */ let yAxis = svg.append("g") .attr("class", "y_axis") .attr( "transform", "translate(" + [ margin.left, 0 ].join(",") + ")" ) .call( d3.axisLeft(y) .ticks(nDates) .tickSize(-width + margin.left + margin.right) .tickFormat(function (d, i) { return dateStrings[i]; }) ); /* バーを描画する */ let innerWidth = width - margin.left - margin.right; // 内側の表示部分 (横幅) let innerHeight = height - margin.bottom - margin.top; // 内側の表示部分 (高さ) let barWidth = innerWidth / 24; // バーの横幅 let barheight = innerHeight / nDates; let bars = svg.selectAll("rect") .data(divided) .enter() .append("rect") .attr("x", function (d, i) { let start = d[0]; return x(toHour(start)); }) .attr("y", function (d, i) { let start = d[0]; let startYmd = start.toLocaleString().split(" ")[0]; let startMd = startYmd.substring(5); // 2018/02/15 → 02-15 return y(dateStrings.indexOf(startMd)); }) .attr("height", barheight) .attr("width", function (d, i) { let milliSecInDay = 86400000; // Date - Date でミリ秒が返るため let start = d[0]; let finish = d[1]; return innerWidth * (finish - start) / milliSecInDay; }) .attr("fill", function (d, i) { let colornum = d[2]; let color = "blue"; if (colornum == 10) { color = "red"; } else if (colornum == 11) { color = "green"; } return color; }) .style("opacity", 0.6); /* その日の始めから何秒経過したかを返す */ function toSec(d) { let elapsed = d.getHours() * 60 * 60 + d.getMinutes() * 60 + d.getSeconds(); return elapsed; } /* その日の始めから何時間経過したかを返す */ function toHour(d) { let sec = toSec(d); // 経過秒 let secInDay = 86400; // 24 * 60 * 60 return sec / secInDay * 24; } /* 目盛りの日付文字列の位置を調整する */ yAxis.selectAll("g.tick") .selectAll("text") .attr( "transform", "translate(" + [ 0, barheight / 2 ].join(",") + ")" ); } catch (err) { errorFunction(err); } }); } まとめ 先人様のソースを見ることでかなり理解を深められました。これで工場の稼働時間などの可視化なども可能になりそうですね。 参考にさせていただきました D3.js -- 睡眠時間をグラフにプロットする https://zdassen.hatenablog.com/entry/2018/02/21/012842 D3.js -- x軸、y軸の目盛りを描画する & グリッドを描画する https://zdassen.hatenablog.com/entry/2018/02/15/131910 JavaScript -- 日付変更線をまたぐデータを翌日の00:00:00で分割する https://zdassen.hatenablog.com/entry/2018/02/13/234150
- 投稿日:2022-01-12T13:58:22+09:00
ぼーっと眺める自動スクロール用Bookmarkletを作った
0.初めに 私は、非エンジニアなのでこの記事は初心者向けです。 Qiitaや掲示板を閲覧するときに、自動スクロールして、ぼーっと眺めたかったのでそういうブックマークレットを探してみました。 1.見つけたもの 以下のページにひな形になる情報がありました。 速度調整できる自動スクロールのブックマークレット | MIII.me https://miii.me/4326.html 個人的には、以下の点が、不便だったので変更してみました。 ブックマークバーから起動/停止はちょっと使いづらい スクロール速度が変更できない 2.作った物 以下の画像の通りです。 処理の流れは以下。 ブックマークバーで「スクロ」クリック スクロールボタンが常に画面左上部に表示される スクロールボタンを押すとスクロール速度を入力するプロンプトが表示 プロンプトでOKを押すとスクロール開始 もう1回スクロールボタンを押すと停止 3.ソース ソース var newBtn = document.createElement("button"); var m; newBtn.innerHTML = "スクロール"; newBtn.onclick = () => { console.log(`ボタン${newBtn.innerHTML}が押されました!`); if(!m){var n=prompt("スピード(数値が大きいと遅い)",60);m=setInterval(function(s){scrollBy(0,s||2)},n)}else{clearInterval(m);m=0} }; document.body.parentNode.insertBefore(newBtn,document.body.parentNode.firstElementChild); newBtn.style.position = "fixed"; newBtn.style.top = "2px"; newBtn.style.left = "2px"; newBtn.style.padding = "8px"; newBtn.style.zIndex = "9999"; ボタンを生成して、onclickでスクロール/スクロール停止する関数付けて、bodyの先頭ノードにボタンを追加、styleで表示位置を指定しています。 ボタンの生成は以下のサイトを参考にしました。 JavaScriptでcreateElementメソッドを使いHTMLを動的生成する方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン https://techacademy.jp/magazine/36505 ボタンのノード追加は以下のサイトを参考にしました。 脱jQuery .after() .before() .insertAfter() .appendTo() .prepend() .prependTo() | q-Az https://q-az.net/none-jquery-after-before-appendto-prepend/ bookmarkletへの変換は、以下のサイトを利用しています。 Bookmarklet スクリプト変換 https://ytyng.github.io/bookmarklet-script-compress/ 生成したBookmarkletは以下です。 Bookmarklet javascript:var%20newBtn%3Ddocument.createElement(%22button%22)%3Bvar%20m%3BnewBtn.innerHTML%3D%22%E3%82%B9%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AB%22%3BnewBtn.onclick%3D()%3D%3E%7Bconsole.log(%60%E3%83%9C%E3%82%BF%E3%83%B3%24%7BnewBtn.innerHTML%7D%E3%81%8C%E6%8A%BC%E3%81%95%E3%82%8C%E3%81%BE%E3%81%97%E3%81%9F%EF%BC%81%60)%3Bif(!m)%7Bvar%20n%3Dprompt(%22%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89%EF%BC%88%E6%95%B0%E5%80%A4%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%A8%E9%81%85%E3%81%84%EF%BC%89%22%2C60)%3Bm%3DsetInterval(function(s)%7BscrollBy(0%2Cs%7C%7C2)%7D%2Cn)%7Delse%7BclearInterval(m)%3Bm%3D0%7D%7D%3Bdocument.body.parentNode.insertBefore(newBtn%2Cdocument.body.parentNode.firstElementChild)%3BnewBtn.style.position%3D%22fixed%22%3BnewBtn.style.top%3D%222px%22%3BnewBtn.style.left%3D%222px%22%3BnewBtn.style.padding%3D%228px%22%3BnewBtn.style.zIndex%3D%229999%22%3Bvoid(0); 4.終わりに ブックマークレットは、とても便利だし、ブラウザさえあれば試せるので、初心者向けだと思います。 Braveみたいな広告抑止機能があるブラウザーで使うと某巨大掲示板閲覧がはかどると思います。 以 上
- 投稿日:2022-01-12T13:10:00+09:00
高さ対直径が1:1な円柱の空気抵抗について完全に理解したかもしれない
何故にそんなことを考えたの? 当初の目的は、「空気抵抗を最小限にするにはどんな断面がいいの?」という疑問でした。 そのためにこの記事を参考にジューコフスキー翼を作ってみて、その抗力を調べようと思ったのですが、 「抗力係数が分からねぇ…」という根本的な問題にぶち当たりました(当然ですが)。 で、それじゃあどうやって抗力を求めるの? そこで色々とGoogle先生に聞いてみるも、ほぼ答えは $$ D = \frac{1}{2} \rho v^2 C_d $$ (ρは空気の密度、vは速度、Cdは抗力係数) この記述以外がなかなか見当たらねぇ…。と悩んでいたそんなところ、 こんなサイトがあるじゃありませんか。 (現在は撤回されていますが、僕がアクセスした当時は抗力の試算方法も載っていました) こりゃすげぇ!!と早速試しに円柱の空気抵抗を計算してみたら、既存の式に比べて値が異様に高い…。 (従来の式で約48[N]に対して、上のサイトの方式(以降、「長谷川式」)の抗力は約5023[N]) (円柱は半径0.5[m]の高さ1[m]、標高0[m]で15[℃]の状態、風速は40[km/h]を想定しました) 上のサイトの管理者(以降、長谷川様)に問い合わせても、 この2、3日熟慮しましたが、抗力計算結果の間違いの理由が解明できておりません。 とのこと。 じゃあ、詰んだの? んな訳はあるめぇ、他に方法があるはずだ、と思い色々な値を見てみました。 その紆余曲折は長い上に面白くないので割愛しますが、ある値に行きつきました。 固有音響インピーダンス 簡単に言えば音の伝わりづらさです。交流電圧とインピーダンスの関係と同じです。 長谷川様の仮説では、 物体が空気中を移動するとき、物体の前面には空気が圧縮されて高気圧域が、後面には空気が膨張して低気圧域が発生する。 ということになっています。これは僕も正しいと思います。ですが同時に、 空気中に生じた気圧差は音速で解消されるのですが、物体の移動が続くと物体の表面に気圧差は発生し続けるのです。 とエビデンスなしに述べております。これには疑問符が付きました。 恐らく、長谷川様の仮説のバックボーンとなっている本、 "Understanding Flight"にそう書いてあったのを鵜呑みにしたのでは、と思います。 その点について長谷川様に問い合わせてみても、 小生は「気圧差の解消速度はその場の音の伝播速度」と考えています。もちろん流速でも移動速度でもありません。 「その場の音の伝播速度」とはその場の「音響インピーダンス」を考慮してのことで、上空3000mの音速を考慮してセスナの揚力を計算しています。 という回答で、いまいちピンと来ません。 音響インピーダンスは $$ \frac{p}{Sv} ( \frac{[Pa]}{[m^2]・[m/s]} ) $$ で求まるのですが、長谷川式揚力の計算式 $$ \frac{v}{c} ・ \sin \theta ・ \frac{p}{101325} ・ 1atm ・ S ・ \cos \theta ( \frac{[m/s]}{[m/s]}・\frac{[Pa]}{[Pa]}・[Pa]・[m^2] ) $$ (v:流速、c:その場の音速、p:雰囲気圧、S:表面積、θ:表面の傾き) のどこにも音響インピーダンスを考慮した部分が出てきていません。 さて、何故「音響インピーダンス」にたどり着いたかという話をしていませんでしたが、 気圧差を音速で解消しようとするけれども、「音響インピーダンス」に邪魔されて 実際には音速でない速度で解消されていると考えたからです。 (例えば、団扇で扇いでから実際に風が来るまで意外とタイムラグがあると思います) 話を戻して、数式に空気の固有音響インピーダンスを登場させましょう。 空気の固有音響インピーダンスは $$ Z = \rho c ([kg/m^3]・[m/s]) = \frac{p_a}{v_a} (\frac{[Pa]}{[m/s]}) $$ (ρ:その場の密度、c:その場の音速、pa:その場の気圧、va:その場の速度) (厳密には疎密波が正弦波の場合) で求まるので、その場の速度vaを求めたければ $$ v_a = \frac{p_a}{\rho c} $$ となります。ところで、長谷川様の仮説では物体の前方で上昇した気圧(=物体の後方で降下した気圧)は $$ \frac{v}{c} \sin \theta ・ p \sin \theta = \frac{vp}{c} \sin^2 \theta $$ となるため、式をまとめると $$ v_a = \frac{vp \sin^2 \theta}{\rho c^2} $$ となります。僕はこのvaが気圧差を解消しようとする流速だと判断しました。そしてそれを利用して、 $$ D = \sum \frac{1}{2} \rho v_a^2 h \sqrt{\varDelta x^2 + \varDelta y^2} $$ (h:物体の高さ、Δx:x軸上の微小変化量、Δy:y軸上の微小変化量) と立式してみました。 レッツ実践 グラフの描画にはplotly.jsを使用しています。 cylinder.js // 定数群 const N = 1000; // 分割数[個] const d0 = 1; // 円柱の直径[m] const l0 = 1; // 円柱の長さ[m] const cd = 0.63; // 直径:高さが1:1の円柱の抗力係数 const sonic = 340.6520138; // 15℃時の音速[m/s] const density = 1.225; // 空気の密度[kg/m^3] const pressure = 101325; // 1気圧[Pa] const graphWidth = 720; // 表示するグラフの横幅[px] const graphHeight = 480; // 表示するグラフの高さ[px] // 共通で使う配列 const arr = [ ...Array( N ) ]; // 円を描く関数 const cylinder = ( d ) => { const r = d / 2; return ( t ) => { return { x: r * Math.cos( t ), y: r * Math.sin( t ) }; }; }; // 円を作る const foil0 = cylinder( d0 ); // 作った円を点にプロット const xyList = arr.map( ( k, i ) => i ).reduce( ( p, i ) => { const tmp = foil0( i * 2 * Math.PI / N ); p.x.push( tmp.x ); p.y.push( tmp.y ); return( p ); }, { x: [], y: [] } ); // 速度のx軸を作る(0~音速まで) const xSpeedList = arr.map( ( k, i ) => i * sonic / N ); // 従来の式での抗力のリストを作る const yCDragList = arr.map( ( k, i ) => xSpeedList[ i ] ** 2 * density * d0 * l0 * cd / 2 ); // 速度対長谷川式抗力のリストを作る const hDrag = ( v ) => arr.map( ( k, i ) => { const tmpX = xyList.x[ i ] - xyList.x[ i < N - 1 ? i + 1 : 0 ]; const tmpY = xyList.y[ i ] - xyList.y[ i < N - 1 ? i + 1 : 0 ]; const delta = Math.sqrt( tmpY ** 2 + tmpX ** 2 ); return( ( tmpY / delta ) ** 2 * delta * l0 * pressure * v / sonic ); } ).reduce( ( p, c ) => p + c, 0 ); const yHDragList = arr.map( ( k, i ) => hDrag( xSpeedList[ i ] ) ); // 速度対長谷川式抗力(前方投影面積版)のリストを作る const yHDragList2 = arr.map( ( k, i ) => 0.35 * d0 * l0 * pressure * xSpeedList[ i ] / sonic ); // 速度対樺沢式抗力のリストを作る const kDrag = ( v ) => arr.map( ( k, i ) => { const tmpX = xyList.x[ i ] - xyList.x[ i < N - 1 ? i + 1 : 0 ]; const tmpY = xyList.y[ i ] - xyList.y[ i < N - 1 ? i + 1 : 0 ]; const delta = Math.sqrt( tmpY ** 2 + tmpX ** 2 ); const accel = ( ( tmpY / delta ) ** 2 * pressure * v / ( density * sonic ** 2 ) ); return( accel ** 2 * density * delta * l0 / 2 ); } ).reduce( ( p, c ) => p + c, 0 ); const yKDragList = arr.map( ( k, i ) => kDrag( xSpeedList[ i ] ) ); // プロットした速度対抗力を線グラフとして繋ぐ const sCDrag = { x: xSpeedList, y: yCDragList, type: 'scatter', mode: 'lines', name: 'Conventional' }; const sHDrag = { x: xSpeedList, y: yHDragList, type: 'scatter', mode: 'lines', name: 'Hasegawa-1' }; const sHDrag2 = { x: xSpeedList, y: yHDragList2, type: 'scatter', mode: 'lines', name: 'Hasegawa-2' }; const sKDrag = { x: xSpeedList, y: yKDragList, type: 'scatter', mode: 'lines', name: 'Kabasawa-1' }; // 表示するグラフの配列を入れる const veloData = [ sCDrag, sHDrag, sHDrag2, sKDrag ]; // レイアウト設定 const veloLayout = { height: graphHeight, width: graphWidth, xaxis: { range: [ Math.min( ...xSpeedList ), Math.max( ...xSpeedList ) ], title: 'velocity[m/s]' }, yaxis: { range: [ Math.min( ...yCDragList ), Math.max( ...yCDragList ) ], title: 'aerodynamic drag[N]' }, title: 'Drag on the Cylinder vs Speed' }; // 実際の描画(veloの名が付いたdivタグの内容として表示) Plotly.newPlot( 'velo', veloData, veloLayout, { editable: true, scrollZoom: true, showLink: false, displaylogo: false, modeBarButtonsToRemove: ['sendDataToCloud'] } ); cylinder.html <!doctype html> <html lang='ja'> <head> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> </head> <body> <div id="velo"><!-- ここに速度対抗力のグラフを表示する --></div> <script src="cylinder.js"></script> </body> </html> \結果発表~!!/ 青線が従来の式(抗力係数0.63)(Conventional)、 橙線が長谷川式抗力(Hasegawa-1)、 緑線が前方投影面積から求めた長谷川式抗力に0.35をかけたもの(Hasegawa-2)、 赤線が僕の式(Kabasawa-1)です。 青線と赤線がいい感じに近似していますね。 また、緑線が当たらずと言えども遠からずなのも面白いところです。 (長谷川様曰く、緑線の抗力は実測値に基づいて経験的に0.35という係数をかけたそうです) 課題 高さ対直径が変わると抗力係数が変化しますが、それについていけないところです。 また、円柱以外の立体図形に対して有効なのか分かりません。 【緩募】マサカリ 僕は流体力学や航空力学についてはずぶのド素人なので、いい感じのマサカリが飛んでくると喜びます。 皆様と一緒にこの方式をより良いものとするためにも、是非ご協力をお願いいたします。
- 投稿日:2022-01-12T11:08:59+09:00
インタープリタを作る その35
概要 インタープリタを作ってみた。 jsforthを使ってみた。 サウンド拡張する。 ドレミ、やってみた。 サンプルコード play" ドドソソララソソファファミミレレドドソソファファミミレレソソファファミミレレドドソソララソソファファミミレレド" 成果物 以上。
- 投稿日:2022-01-12T09:55:22+09:00
インタープリタを作る その34
概要 インタープリタを作ってみた。 jsforthを使ってみた。 グラフィック拡張する。 sin波、やってみた。 写真 サンプルコード : test 400 1 do i i sin susume loop ; test 成果物 以上。
- 投稿日:2022-01-12T09:14:36+09:00
JavaScriptのClassでprivateメソッドを実装すると「Parsing error: Unexpected character '#' eslint」エラーになる
はじめに ESLintを設定している時に、以下の図のようなエラーが発生した。 今回はこのエラーを解消する方法について調べてみたのでその備忘録を残す。 ESLintについて を参照。 ESLintのparserOptionsを指定する JavaScriptsのprivateメソッドはes2022の機能なため、以下のようにESLintの設定を変える必要がある。 // .eslint.json { ... "parserOptions": { "ecmaVersion": 13 }, ... } ※コメントでご指摘を頂いたとおり、以下の方法ではなくESLint自体の設定でカバーできる問題でした。 上記のエラーを解消するには、yarn add --dev @babel/eslint-parser等でライブラリをインストールし、後は公式にあるように以下のようにparserを追記すればいい。 こうすると、ESLintが実装されている構文を解釈できるようになりエラーが発生しなくなる。 参考:Specifying Parser Options 参考:Parsing error: Unexpected character '#' #1542
- 投稿日:2022-01-12T09:06:06+09:00
グランデータのマイページで初期パスワードを変更する方法
電気使用料を調べるためにマイページへログイン。 ログイン → 初期パスワード入力 → メール認証 → パスワード変更画面 するとパスワード変更画面で「登録する」ボタンが反応しません。 しょうがないのでデバッグさせていただきました。 結論だけ書きます。 パスワードは「半角英数字10文字以上20文字以下で入力」。 コンソールからsubmitを送信 $('#submenu_password_init').submit(); 無事にログインできました。 ※デバッグ風景 エラーメッセージが出ないのでパスワードの入力規則が分かりにくかった。 (よく見たら画面に書いてありました)
- 投稿日:2022-01-12T08:53:11+09:00
インタープリタを作る その33
概要 インタープリタを作ってみた。 jsforthを使ってみた。 グラフィック拡張する。 kame作ってみた。 写真 サンプルコード : koch 5 walk -60 turn 5 walk 120 turn 5 walk -60 turn 5 walk ; : koch1 koch -60 turn koch 120 turn koch -60 turn koch ; : koch2 koch1 -60 turn koch1 120 turn koch1 -60 turn koch1 ; koch2 -60 turn koch2 120 turn koch2 -60 turn koch2 成果物 以上。
- 投稿日:2022-01-12T04:33:20+09:00
webview.hostObjects が async で失敗するのをなんとかする
JavaScript addEventListener('_exe.Ready',e=>{ var url = `https://script.google.com/macros/s/SampleDeployId/exec`; var text = `SampleText: Fixed newly exposed boat not showing up in the boat yard menu Changed contraptions to drop resources and inventory objects (crates) to drop resources even when killed with fire. Previously anything killed by fire would drop nothing.` chrome.webview.hostObjects.exe.PostError(url,text).then(r=>{ console.log(r)// null、async失敗 }) _exe.post(url,text).then(r=>{ console.log(r)// async成功 }) }) _exe = new class { constructor(){ this.promise = {} //this.on = {} addEventListener('Bridge.Ready',e=>{ chrome.webview.hostObjects.exe.GetMethods().then(a=>{ a.forEach(s=>this.addMethod(...s.split(','))) chrome.webview.addEventListener('message',e=>{ this.message(JSON.parse(e.data)) }) dispatchEvent(new Event('_exe.Ready')) }) },true) } addMethod(m,attr){ var s = m[0].toLowerCase() + m.slice(1); if(this[s]) return if(attr=='async'){ this[s] = (...a)=>new _exe.Promise.Message(m,...a) }else{ this[s] = (...a)=>new _exe.Promise.Json(m,...a) } } message(v){ switch(true){ //case ('type' in v): _exe.on[v.type](v); break case ('id' in v) : this.promise[v.id].resolve(v.value); break default:console.log(v) } } } _exe.Promise = class _exePromise{ constructor(){this.hook = ()=>{}} then(resolve){ this.hook = resolve return this } } _exe.Promise.id = 0 _exe.Promise.Json = class _exePromiseJson extends _exe.Promise{ constructor(s,...a){super() chrome.webview.hostObjects.exe[s](...a).then(r=>{ try{this.hook(JSON.parse(r))} catch(e){this.hook(r)} }) } } _exe.Promise.Message = class _exePromiseMessage extends _exe.Promise{ constructor(s,...a){super() this.id = ++_exe.Promise.id _exe.promise[this.id] = this chrome.webview.hostObjects.exe[s](...a,this.id) } resolve(r){ this.hook(r) delete _exe.promise[this.id] } } Bridge.cs public class Bridge{ protected CoreWebView2 core = null!; public Bridge(WebView2 view) { view.NavigationCompleted+=(s,e) => { core = view.CoreWebView2; core.AddHostObjectToScript("exe",this); Dispatch("Bridge.Ready"); }; } //nullが返る public async Task<string> PostError(string url,string data) { var content = new StringContent(data,Encoding.UTF8); using(var client = new HttpClient()) { var response = await client.PostAsync(url,content); var s = await response.Content.ReadAsStringAsync(); return s; } } //手動でResolve public async void Post(string url,string data,int resolve) { var content = new StringContent(data, Encoding.UTF8); using (var client = new HttpClient()){ var response = await client.PostAsync(url, content); var s = await response.Content.ReadAsStringAsync(); Resolve(resolve,s); } } class ResolveData { public int id { get; set; } = 0; public object value { get; set; } = null!; } protected void Resolve(int i,object v) { var r = new ResolveData() { id=i,value=v }; var s = JsonSerializer.Serialize(r); core?.PostWebMessageAsString(s); } protected async void Dispatch(string type) { if(core!=null) { var s = $"dispatchEvent(new Event('{type}'))"; var r = await core.ExecuteScriptAsync(s); } } public string[] GetMethods(){ var objectMethods = typeof(Object).GetMethods(); var async = typeof(AsyncStateMachineAttribute); var methods = new List<string>(); foreach(MethodInfo m in GetType().GetMethods()) { if(!Array.Exists(objectMethods,v => { return v.Name==m.Name; })){ if(m.GetCustomAttribute(async)==null) { methods.Add(m.Name); } else { methods.Add($"{m.Name},async"); } } } return methods.ToArray(); } }