- 投稿日:2021-01-27T23:01:16+09:00
【React Native iOS】外部アプリからファイルを開く方法
※注意:この記事はiOSのことだけ書いてます。
先に結論
- Document Typesを設定する
- Linkingを使ってファイルパスを取得する
以上。
何がしたいのか
個人でReact Nativeを使ってアプリ開発をしている中で、他のアプリからファイルを受け取る必要があり、今回実装してみました。
正確になんて言うのか、言葉はわからないのですが……これです?
共有シートから、特定のアプリでファイルを開くヤツ。
メールやSafari、AirDropで共有されたファイルも開けるようになります。……なんて言うのが正しいの?
実装環境
- React Native 0.63.4
- XCode 12.3
なおRNプロジェクトの作成方法は割愛します。
? 外部アプリからファイルを取得する
1. 受け取るファイルの種類を設定する
初っ端からXcodeを開きます。
Projectを開いたら、Target < [APP名] < Info < Document Typesを開いて、アコーディオン内の+ボタンを押してください。
- Nameは適当に、ファイル形式の種類の名前を入れます。
Typeには、予め決められているMIMEのようなものを入れます。正しくは
Uniform Type Identifier (UTI)と言うらしいです。
必要な値はここから探せます。その他、独自形式も定義できるみたいです。
Handler Rankは指定した形式のファイルに対して、閲覧者なのか作成者なのかを宣言して、他のアプリとのランク付けをするもの、らしい、です。
値 意味 Owner 指定した種類のファイルを作成します Default 指定した種類のファイルを開きます Alternate 指定した種類のファイルのセカンダリビューアー None 指定した種類のファイルに対して何もしない 2. 受け取ったファイルをRNに送るためのコードを書く
次に、受け取ったファイル(正しくはファイルのパス)を、React NativeのJavaScript側に送るためのコードを書きます。
コードを書くファイルは、AppDelegate.mです。
追加するコードは、(大分わかりにくいですが……)以下の緑色のコードです。
上の方でReact/RCTLinkingManager.hをインポートして、あとは下の方で3行だけコードを入れれば、ひとまず完成です。AppDelegate.m#import "AppDelegate.h" #import <React/RCTBridge.h> #import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> + #import <React/RCTLinkingManager.h> ~~~中略~~~ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ~~中略~~ } + - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { + return [RCTLinkingManager application:application openURL:url options:options]; + }3. JS側でファイルパスを受け取る
残るは、ReactNative側でファイルパスを受け取るだけです。
コードから予想できた方も多いと思いますが、URL Schemeで使うLinkingを使ってパスを取得します。
というか2と3に関しては、ドキュメントそのままです。const handler = (filePath: string) => { // 処理内容 }; useEffect(() => { // アプリ起動前に呼ばれる Linking.getInitialURL().then((filePath) => { if (filePath) handler(filePath); }); // アプリ起動後に呼ばれる Linking.addEventListener('url', (event) => handler(event.url)); }, []);URL Schemeで取得するURLの多くは、
https://~~やmailto:~~だと思いますが、ここで取得されるパスはfile:///~~~になっていて、iOS内部の絶対パスが渡ってきます。4. ファイルパスを使って処理する
ここに関しては、必要に応じて処理をしてください。
私はreact-native-fsを導入してreadFileで読み込みました。? LSSupportsOpeningDocumentsInPlaceと共存させる方法
iOS11から追加されたファイル.appから、各アプリのディレクトリにアクセスできるヤツ。
これの有効に必要な
LSSupportsOpeningDocumentsInPlaceをオンにしていると、上記の方法で取得したファイルパスを使っても、No such file or directoryと怒られてしまう場合があります。
LSSupportsOpeningDocumentsInPlaceを有効にすると、ファイルをコピーせず直接オリジナルのファイルを参照しにいきます。
iOSはサンドボックスの制限が厳しいので、(正確な理由はわからんですが)おそらくJS側からオリジナルのファイルがあるパスにアクセスする権限がないのが原因かなと。回避策として、tmpディレクトリにファイルをコピーしてしまう事にしました。
AppDelegate.m- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { NSString* urlPath = url.path; if(![[NSFileManager defaultManager] isReadableFileAtPath:urlPath]) { if([url startAccessingSecurityScopedResource]) { NSString* destPath = [NSString stringWithFormat:@"%@/%@", NSTemporaryDirectory(), [url.path lastPathComponent]]; if(![[NSFileManager defaultManager] copyItemAtPath:urlPath toPath:destPath error:nil]) { [[NSFileManager defaultManager] removeItemAtPath:destPath error:nil]; [[NSFileManager defaultManager] copyItemAtPath:urlPath toPath:destPath error:nil]; } [url stopAccessingSecurityScopedResource]; NSURL* destURL = [NSURL fileURLWithPath:destPath]; return [RCTLinkingManager application:application openURL:destURL options:options]; } } return [RCTLinkingManager application:application openURL:url options:options]; }読み取り権限がないファイルパスだった場合のみ、アプリのtempDirにファイルをコピーして、RNにコピーしたファイルのパスを渡すように変更しました。
これで、JS側からもファイルを読みに行くことができました?〆
普段Web言語ばかり扱っているので、こうしてネイティブ部分のコードに触れて理解できるようになると楽しくなってきますね。
時間を作って、Obj-CやSwiftもしっかり勉強したいと思いました。なおネイティブアプリをまともに書いた経験が無いので、間違いなどあればご指摘ください?♂️
- 投稿日:2021-01-27T22:53:38+09:00
【JavaScript学習記録】アルファベットの配列の作り方
PHPでは、以下のように簡単にアルファベットの配列を作ることができます。
$alphabets = range('a', 'z');JavaScriptでは、どのようにして作るのだろう。
今日はそれを調べてみましたので、アウトプットします。※ 下記を参考にさせて頂きました
http://2amcode.hatenablog.com/entry/2017/08/22/102156const start = "a" . charCodeAt(0); const alphabets = Array.apply(null, new Array(26)).map((v, i) => { return String.fromCharCode(start + i); }, {})コードを一行ずつみていきます。
まずは一行目の「charCodeAt(0)」。
charCodeAt(n)は、Stringオブジェクトで利用可能なメンバーです。
n + 1番目の文字をLatin-1コードに変換します。
※ Latin-1・・・ラテンアルファベットの文字コード標準。二行目の「.apply()」、「.map()」。
.apply()は、関数を呼び出すメソッドです。【構文】 関数名.apply(関数の処理の対象となる要素, 関数で使う引数(配列のみ));
.map()は、コールバック関数によって新しい配列を生成します。【構文】 関数名.map([要素], [インデックス], [元配列]) => 変更後の要素三行目の「String」、「fromCharCode(start + i)」。
Stringは、文字列型の値を扱うラッパーオブジェクトです。
文字列の抽出や加工、検索等を行う為の機能を提供します。
fromCharCode(c1, c2...)は、Stringオブジェクトで利用可能なメンバーの一つです。
Latin-1コードc1,c2...を文字に変換します。
startで定義したラテンコードをアルファベットにどんどん変換して返しているということでしょうか。
PHPと比較すると大分難しく感じますが、少しずつ理解できるよう努めていきたいと思います。
今回の記事の内容に不備等ございましたら、後学の為にご指摘頂けますと幸いです。
- 投稿日:2021-01-27T22:47:29+09:00
Reactにおける基本的なライフサイクルメソッド
hooksの登場により、classコンポーネントにしかなかった機能が使えるようになり、あらゆる場面で関数コンポーネントを使えるようになりました。
とはいえ、いきなりclassコンポーネントに関する事項を飛ばしてhooksの内容を学習するのはお勧めできません。classコンポーネントの学習から始め、classコンポーネントにおけるライフサイクルメソッドなどの概念を理解してからのほうがhooksの学習に入った際にスムーズに理解できると思います。1
そこで、ここではclassコンポーネントのライフサイクルメソッドについてまとめます。
(尚、ここではshouldComponentUpdateなどの使用されるケースが稀なものは除いています。)ライフサイクルについて
コンポーネントには、画面上に表示され、再レンダリング(更新)を何度か経て、やがて表示されなくなるまでの流れがあります。この一連の流れがライフサイクルと呼ばれるもので、この流れは3つの期間に大別できます。
マウント時(Mounting)
コンポーネントが画面上に表示されるまでの期間にあたります。この期間では、constructor、render、componentDidMountの主に3つが呼ばれます。
constructor
最初に呼ばれます。後述のrenderメソッドと同様、画面にコンポーネントが表示される前に呼び出されます。stateの初期化などはここで行います。ただし、ここでsetStateメソッドを呼び出してはいけません。尚、データの読み込みもここで行うことは可能ですが、後述のcomponentDidMountで行うことが推奨されています。
render
renderメソッドは、唯一定義が必須となっています。このメソッドが呼ばれると、JSXの内容がDOMに追加され、コンポーネントが画面に表示されます。これが初回のレンダリングになります。
componentDidMount
初回レンダリング後に1度限りで呼ばれます。データの読み込みなどはこちらで行います。
更新時(Updating)
stateが更新されたり、親から新たなpropsを受け取ったりした場合に、この期間で再レンダリングされ、更新されます。以下のrender→componentDidUpdateというこの期間の流れは、コンポーネントが表示されなくなるまでの間、更新が必要になる度に繰り返されます。
render
マウント時に呼ばれたrenderメソッドですが、ここで再び呼ばれ、再レンダリングが行われます。
componentDidUpdate
コンポーネントがアンマウントされる(コンポーネントがDOMから削除され、画面に表示されなくなる)までの間、コンポーネントの再レンダリングが起こった(renderメソッドが呼ばれた)度に呼ばれます。
マウント解除時(Unmounting)
他のコンポーネントを表示するなどの理由により現在のコンポーネントが表示されなくなる(マウントが解除される)ことになったときがこの期間です。
componentWillUnmount
マウント解除時に1度限りで呼ばれます。ここでネットワークリクエストのキャンセルなどを行います。
その他のメソッド
以上の他にも、shouldComponentUpdate、getDerivedStateFromProps、getSnapshotBeforeUpdateといったものがあります。
しかし、これらは滅多に使われないものなので、初めは以上の5つのメソッドを理解できていれば良いと思います。
この理由の1つに、hooksのuseEffectがあります。useEffectは、classコンポーネントのライフサイクルメソッドに相当する機能であり、ライフサイクルメソッドを理解していればuseEffectも理解しやすいです。私はReactを学習するのにUdemyの講座「 Modern React with Redux [2020 Update] 」( https://www.udemy.com/course/react-redux/ )を利用しました。この講座でも、先述の理由から、classコンポーネントの解説がhooksの解説に先行しています。正しい順序で効率的にReactを学習するのにお勧めです。 ↩
- 投稿日:2021-01-27T20:50:00+09:00
[Azure] Azure Event Hubsのイベントをブラウザでリアルタイム受信するサンプルプログラム
これはなに?
Azure Event Hubsのコンシューマ(イベント受信側)をWebブラウザで動かすサンプルです。
ソース全体は https://github.com/sengokyu/Ex.AzureEventHubConsumerOnBrowser に置いてあります。
実行の仕方
事前準備
Event Hubを作成し、接続文字列を取得しておきます。
実行
環境変数を3つ設定します。
環境変数 内容 EVENTHUB_CONNECTION_STRING 取得した接続文字列です。 EVENTHUB_CONSUMER_GROUP 既定では $Defaultです。EVENTHUB_NAME 作成したEvent Hubの名前です。 パッケージをインストールしてビルドします。
npm install npm build
dist/index.htmlをブラウザで開きます。開発者コンソールを開きます。イベントを送信してみます。
node src/producer/send-event.js実行結果
このような感じにイベントが届きます。
はまったところ
Webpack 5では
processを定義してくれなくなったため、自前でwebpack.config.jsに書く必要がありました。
- 投稿日:2021-01-27T20:50:00+09:00
[Azure] Azure Event Hubsのイベントをブラウザでリアルタイム受信するサンプル
これはなに?
Azure Event Hubsのコンシューマ(イベント受信側)をWebブラウザで動かすサンプルです。
ソース全体は https://github.com/sengokyu/Ex.AzureEventHubConsumerOnBrowser に置いてあります。
実行の仕方
事前準備
Event Hubを作成し、接続文字列を取得しておきます。
実行
環境変数を3つ設定します。
環境変数 内容 EVENTHUB_CONNECTION_STRING 取得した接続文字列です。 EVENTHUB_CONSUMER_GROUP 既定では $Defaultです。EVENTHUB_NAME 作成したEvent Hubの名前です。 パッケージをインストールしてビルドします。
npm install npm build
dist/index.htmlをブラウザで開きます。開発者コンソールを開きます。イベントを送信してみます。
node src/producer/send-event.js実行結果
このような感じにイベントが届きます。
はまったところ
Webpack 5では
processを定義してくれなくなったため、自前でwebpack.config.jsに書く必要がありました。この実装の弱点
接続文字列がJavaScript内にあるので、外からはアクセスできない環境でしか活用できません。
- 投稿日:2021-01-27T20:34:15+09:00
診断サービス?をつくってみたんだけども
開発者のレベル
ポケットモンスター緑・赤で例えるならばタケシに会うレベル
動いたらいいな♡って念じながらプログラミングをやっています診断サービスをつくろうと思った理由
アプリを開発している知り合いのボドゲ―マーに「診断アプリはオススメだよ」って言われたからです。
いつかアプリ開発にも手を出したいよ~~。
ゲームとかもつくりたい。
そして広告収入という名の不労所得がほしい。つくったサービス
99%の確率で私の好きなボードゲームであるバラージをおススメしてくれる私得の診断サービスです。出オチ100%である。
実はsakuraのサーバーに移植する前はAWSのS3にコードを放り込むだけという適当なものをTwitterで公開してました。
遊んでくれた方々に感謝。バラージを布教したいので、99%の確率でバラージをおすすめするボドゲ診断サービスを作ってみました! https://t.co/jSB24ZYWug pic.twitter.com/w2dq7kcOuZ
— 黛 (まゆずみ) (@t12200301) October 3, 2020どうやってつくったか?
Webサイトのテンプレートについては下記を参考に自分好みに改造していきました。
https://templatemo.com/tm-539-simple-house選定基準としては
1. Javascriptを利用している(少しでもJavascript触りたい)。
2. 好み
3. シンプル診断機能についてはこちらの記事を参考にしました。
https://qiita.com/bstyle6130/items/c3dfebdceaaef8e3860dなんとな~くは理解できるけど0からこれを作れと言われたらif文をがりがり回すしか思いつかないので、
先駆者の方に感謝!改善点
私の今の力ではすぐに解決できないな~っていうのは下記です。
技術力が高まったらあとで直したいのでメモしておきます。1.診断結果をシェアするときに画像も一緒にツイートさせる。
Twitterの性格診断なんかでよく見る形かと思います。
Twitterのシェア機能では画像を一緒に添付されているのですが、Twitterボタンの生成機能に画像情報を付記する項目が無いので、おそらくこれはTwitterカードをresultごとに動的に生成しているのではないかと予想。
となると、それを自力でなんとかするのは今の段階では無理なので、ちょっと保留にしておきます。2.コードに対する理解を深める。
正直なにがどうなって動いているの?ってところもあるので、もうちょっと修正を効かせるために理解を深めたいです。
3.httpをhttpsにしたい。
この領域に関してはちゃんと理解したいので改めてまとめます!
バラージとはなにか?
バラージは第一次世界大戦後のヨーロッパを舞台に、各国の発電会社のCEOになって発電するボードゲームです。
つくってよかったこと
バラージをやる頻度が高まったよ!
あとはサービスの原理を知っているのと実際にプロダクト?として出すのとでは大きく違うなあという月並みな感想です。
次は何しよっかな~~。
- 投稿日:2021-01-27T20:33:24+09:00
GASによるGmailの日報の自動化
日報ってめんどくさいよね。
みんなも自動化してると思うけど、してへん人のために教えてあげちゃう。
まあGmailの人限定やねんけどな。次の3つでできちゃうわよ。
- GAS(GoogleAppsScript)っていうJavaScriptみたいな言語
- Gmail
- スプレッドシート
ほな、いくで。
スプレッドシートの作成
まず、スプレッドシート開こか。
Chrome使ってたらアプリってやつ左上くらいにあるから、それ押したら出てくるわ。スプレットシートでこんな感じにしてな。
ファイル名:日報
シート名:作業内容スクリプトの作成
次に「ツール→スクリプトエディタ」を開こか。
でコードを書くんや。2つファイル作るで。
前者が日報の下書きを作ってくれるやつで、
後者はスプレッドシートでドラフト保存で保存するを選択したら検知して、前者を呼び出してくれるスクリプトや。
- createGmailDraft.gs
- checksave.gs
createGmailDraft.gs
createGmailDraft.gsfunction createDraft() { //日付 var date = new Date() var today = Utilities.formatDate(date, 'Asia/Tokyo','yyyyMMdd') //スプレッドシートの情報 var ss = SpreadsheetApp.getActive().getSheetByName('作業内容') var values = ss.getDataRange().getValues() //作業時間 var start = values[0][1] var close = values[1][1] var wkHour = values[2][1] //作業内容 var todayTask = values[3][1] var tomorrowTask = values[4][1] //メール内容 var to = 'yamadataichou@taicho.com,test@test.com' var subject = '日報_田中太郎' + today var body = `\ 山田隊長\n\n\ お疲れ様です。田中です。\n\n\ 下記本日の作業やべさ\n\n\ [作業時間]\n\ 開始時間:${start}\n\ 終業時間:${close}\n\ 稼働時間:${wkHour}\n\ [作業内容]\n\ ${todayTask}\n\n\ [作業予定]\n\ ${tomorrowTask}\n\n\ 以上、ヨロピコ丸。` GmailApp.createDraft(to, subject, body) }checksave.gs
checksave.gsfunction checkSave() { //スプレッドシートの情報 var ss = SpreadsheetApp.getActive().getSheetByName('作業内容') var values = ss.getDataRange().getValues() //保存する、しないの部分 var draftSave = values[5][1] if (draftSave==='保存する'){ //メール作成メソッドのお呼び出し createDraft() } //保存しないに変更しとく。 ss.getRange(6,2).setValue('保存しない') }すまん。最初に見た人
createDraft()がコメントアウトなっとったわ。スクリプト完成!
トリガーの設定
次にトリガーを設定するで。
左のバーにカーソル合わせてトリガーをクリック、
右下のトリガーを作成をクリック。
下記を選択する
実行する関数:checkSave
実行するデプロイ:Head
イベントのソース:スプレッドシートから
イベントの種類:変更時
日報作成
スプレッドシートで保存するを選ぶと内容が適用されて下書きが作成される。
終わり
- 投稿日:2021-01-27T20:21:36+09:00
lodashの真偽値判定まとめ
lodashのさまざまな真偽値判定
lodashのisXXXXを使ったりするのですが、undefinedのときtrueだっけ・・・?
と迷うことが多々あったのでまとめてみました。検証バージョンは
4.17.14です。
引数 引数(コード) _.isEmpty() _.isNaN() _.isNil() _.isNull() _.isUndefined() 空文字 '' true false false false false 半角スペース ' ' false false false false false NaN NaN true true false false false null null true false true true false undefined undefined true false true false true 真偽値 true true false false false false 数字 0 true false false false false 文字 'hoge' false false false false false 配列 [0,1,2] false false false false false 空配列 [] true false false false false オブジェクト {hoge:'hoge'} false false false false false 空のオブジェクト {} true false false false false
isEmpty使用するときは要注意ですね。。おまけ
以下で確認しました。
this.checkFuncReturnValue('isEmpty', hoge => _.isEmpty(hoge)); this.checkFuncReturnValue('isNaN', hoge => _.isNaN(hoge)); this.checkFuncReturnValue('isNil', hoge => _.isNil(hoge)); this.checkFuncReturnValue('isNull', hoge => _.isNull(hoge)); this.checkFuncReturnValue('isUndefined', hoge => _.isUndefined(hoge));checkFuncReturnValue(funcName, func) { console.log(funcName); console.log(' blank =>' + func('')); console.log(' halfSpace =>' + _.isEmpty(' ')); console.log(' fullSpace =>' + _.isEmpty(' ')); console.log(' NaN =>' + func(NaN)); console.log(' null =>' + func(null)); console.log(' undefined =>' + func(undefined)); console.log(' true =>' + func(true)); console.log(' number =>' + func(0)); console.log(' string =>' + func('hoge')); console.log(' array =>' + func([0, 1, 2])); console.log(' emptyArray =>' + func([])); console.log(' object =>' + func({ hoge: 'hoge' })); console.log(' emptyObject =>' + func({})); }
- 投稿日:2021-01-27T19:29:05+09:00
javascriptでシューティングゲームみたいなものを作る①
こんにちはrihitoです。
今回はjavascriptでシューティングゲームを作りたいと思います。準備
htmlを書きます
index.html<!DOCTYPE html> <html> <body> <canvas id="main" style="height:400px;width:800px;background:#000000"></canvas> <!--canvasの下にscriptを読み込まないとエラーがでる--> <script src="main.js"></script> </body> </html>canvasに図形を描く
main.jsvar canvas = document.getElementById("main");//canvasを読み込む var ctx = canvas.getContext("2d"); function draw(){ ctx.beginPath() ctx.rect(/*x座標*/50,/*y座標*/50,/*横*/50,/*縦*/50) ctx.fillStyle = "#0000ff" //色を指定 ctx.fill() ctx.arc(10,10,/*半径*/10,0 * Math.PI / 180,360 * Math.PI /180) ctx.fill() ctx.beginclose() } draw();うまく表示できたでしょうか
では、ゲーム作りに入っていきたいと思います!とりあえずplayerを作成
さっきのmain.jsは練習なのですべて消してしまっても構いません。(ファイルは消してはいけません)
codemain.jsvar canvas = document.getElementById("main");//canvasを読み込む var ctx = canvas.getContext("2d"); var px = 10 //player x座標 var py = 120 //player y座標 //playerを描く関数 function player_draw(){ ctx.beginPath() ctx.rect(px,py,10,10) ctx.fillStyle = "#00ff00" ctx.fill() ctx.closePath() } function draw(){ player_draw() } draw();playerを動かしてみる
main.js_16行目~function draw(){ player_draw() px += 5 //追加 } setInterval(draw,10) //10ミリ秒単位で実行 //追加このようにヘビみたいになってしまいました。
なので再描画するときにcanvasをすべて消す必要があります。main.js_16行目~function draw(){ ctx.clearRect(0/*開始地点*/,0,canvas.width/*終了地点*/,canvas.height) //canvasをいったんクリアする //追加 player_draw() px += 5 }うまく動きましたか?
では、playerの速さを変数にします。main.js_3行目~var px = 10 //player x座標 var py = 120 //player y座標 var p_dx = 0 //player xの速さ //追加 var p_dy = 0 //player yの速さ //追加main.js_19行目~function draw(){ ctx.clearRect(0/*開始地点*/,0,canvas.width/*終了地点*/,canvas.height) //canvasをいったんクリアする player_draw() //playerを動かす px += p_dx //追加 py += p_dy //追加 }キーボードで動かせるようにする
main.js_10行目~//playerを描く関数 function player_draw(){ ctx.beginPath() ctx.rect(px,py,10,10) ctx.fillStyle = "#00ff00" ctx.fill() ctx.closePath() } /*追加**********************/ //キーが押されたときに実行される document.onkeydown = function(e){ if(e.key == "ArrowUp"){ //↑ p_dx = 0 p_dy = -1 } if(e.key == "ArrowDown"){//↓ p_dx = 0 p_dy = 1 } } //キーが離されたときに実行される document.onkeyup = function(e){ p_dx = 0 //止める p_dy = 0 } /*追加ここまで****************/今回のコード
index.html<!DOCTYPE html> <html> <body> <canvas id="main" style="height:400px;width:800px;background:#000000"></canvas> <!--canvasの下にscriptを読み込まないとエラーがでる--> <script src="main.js"></script> </body> </html>main.jsvar canvas = document.getElementById("main");//canvasを読み込む var ctx = canvas.getContext("2d"); var px = 10 //player x座標 var py = 120 //player y座標 var p_dx = 0 //player xの速さ var p_dy = 0 //player yの速さ //playerを描く関数 function player_draw(){ ctx.beginPath() ctx.rect(px,py,10,10) ctx.fillStyle = "#00ff00" ctx.fill() ctx.closePath() } //キーが押されたときに実行される document.onkeydown = function(e){ if(e.key == "ArrowUp"){ //↑ p_dx = 0 p_dy = -1 } if(e.key == "ArrowDown"){//↓ p_dx = 0 p_dy = 1 } } //キーが離されたときに実行される document.onkeyup = function(e){ p_dx = 0 //止める p_dy = 0 } function draw(){ ctx.clearRect(0/*開始地点*/,0,canvas.width/*終了地点*/,canvas.height) //canvasをいったんクリアする player_draw() //playerを動かす px += p_dx py += p_dy } setInterval(draw,10) //10ミリ秒単位で実行 draw();
- 投稿日:2021-01-27T18:23:41+09:00
bulletml.jsの研究 その7
概要
bulletml.jsの研究です。
技を調査。全方位
<bulletml> <action label="top"> <repeat> <times>22</times> <action> <fire> <direction type="aim">-30</direction> <bullet> <action> <changeDirection> <direction type="sequence">0</direction> <term>0</term> </changeDirection> </action> </bullet> </fire> <repeat> <times>35</times> <action> <fire> <direction type="sequence">10</direction> <bullet> <action> <changeDirection> <direction type="sequence">0</direction> <term>0</term> </changeDirection> </action> </bullet> </fire> <wait>0</wait> </action> </repeat> <wait>120</wait> </action> </repeat> </action> </bulletml>n-wayの派生型で、全周に向けて一斉に発射する攻撃です。
成果物
https://embed.plnkr.co/plunk/xXUfQnSvcRNBfeTd
以上。
- 投稿日:2021-01-27T18:13:39+09:00
p5.js で様々なパターンを描画してみた #2
1. はじめに
以下Qiita記事の続きになります。
Qiita:p5.js で様々なパターンを描画してみた
https://qiita.com/Haruka-Ogawa/items/8ecb8692bf7455e7f124今回は p5.js を使用して、ハート柄・星柄を描画します。
2. 準備
p5.jsを使用するにあたって、
以下Qiita記事の第2項 を参考に準備します。Qiita:p5.js で様々なパターンを描画してみた > [2. 準備]
https://qiita.com/Haruka-Ogawa/items/8ecb8692bf7455e7f124#2-%E6%BA%96%E5%82%993. コーディング
3-1. ハート柄
p5.js を使用して、ハート柄を描きます。
3-6-1. サンプル
See the Pen p5.js_Heart pattern by Haruka Ogawa (@haruka0121) on CodePen.
3-6-2. 解説
以下に、ハート柄を描くための sketch.jsの内容を示します。
sketch.jsfunction setup() { createCanvas(800, 500); //サイズ background('#191970'); //背景色: 藍色(#191970) } function draw() { noStroke(); //ストローク無効化 let size = 25; //ハートのサイズ let space =40; //ハートの間隔 for (x = 0; x <= width; x += space) { for (y = 0; y <= height; y += space) { fill('#B6FF01'); //図形の塗り潰し:黄緑色(#B6FF01) heart(x, y, size); //ハート描画 } } } function heart(x, y, size) { beginShape(); //ハート描画開始 vertex(x, y); //頂点座標 bezierVertex(x - size / 2, y - size / 2, x - size, y + size / 3, x, y + size); //ベジェ曲線 描画 bezierVertex(x + size, y + size / 3, x + size / 2, y - size / 2, x, y); //ベジェ曲線 描画 endShape(CLOSE); //ハート描画終了 }・ setup関数内 記述
setup()には、サイズ 800px × 500px、背景色 青紫(#191970)の 描画領域を設定します。
function setup() { createCanvas(800, 500); //サイズ background('#191970'); //背景色: 藍色(#191970) }・ draw関数内 記述
draw()には、ハート柄を描くための処理を記述します。
function draw() { noStroke(); //ストローク無効化 let size = 25; //ハートのサイズ let space =40; //ハートの間隔 for (x = 0; x <= width; x += space) { for (y = 0; y <= height; y += space) { fill('#B6FF01'); //図形の塗り潰し:黄緑色(#B6FF01) heart(x, y, size); //ハート描画 } } }使用した関数は、以下の通りです。
関数 説明 noStroke() ストロークの描画を無効にする。 fill() 図形を塗りつぶす色を設定する。 heart() ハートを描画する。draw()の後でheart()の処理内容を記述する。
- noStroke()
noStroke()でストロークの描画を無効にすることができます。
noStroke()の構文は以下の通りです。
noStroke()p5.js Reference: noStroke()
https://p5js.org/reference/#/p5/noStroke
- fill()
fill()で図形を塗りつぶす色を設定することができます。
fill()の構文は以下の通りです。fill(value)p5.js Reference: fill()
https://p5js.org/reference/#/p5/fill
- heart()
ハートを描画するheart()を、この後 作成します。
- heart関数内 記述
heart()には、ハートを描くための処理を記述します。
p5.js Web Editor: Heart shape
https://editor.p5js.org/Mithru/sketches/Hk1N1mMQgfunction heart(x, y, size) { beginShape(); //ハート描画開始 vertex(x, y); //頂点座標 bezierVertex(x - size / 2, y - size / 2, x - size, y + size / 3, x, y + size); //ベジェ曲線 描画 bezierVertex(x + size, y + size / 3, x + size / 2, y - size / 2, x, y); //ベジェ曲線 描画 endShape(CLOSE); //ハート描画終了 }使用した関数は、以下の通りです。
関数 説明 beginShape() 複雑な図形描画の開始。 vertex() 図形の頂点座標を指定する。beginShape()およびendShape()内で使用できる。 bezierVertex() ベジェ曲線の頂点座標を指定する。 endShape() 複雑な図形描画の終了。
- beginShape()
beginShape() と endShape() を使用して、複雑な図形を描画することができます。
beginShape() は図形の頂点の記録を開始します。beginShape()の構文は以下の通りです。
beginShape()p5.js Reference: beginShape()
https://p5js.org/reference/#/p5/beginShape
- vertex()
vertex()は、
beginShape()およびendShape()関数内で、図形の頂点座標を指定します。
vertex()の構文は以下の通りです。vertex(x, y)xに頂点のx座標、yに頂点のy座標を指定します。
p5.js Reference: vertex()
https://p5js.org/reference/#/p5/vertex
- bezierVertex()
bezierVertex()で ベジェ曲線の頂点座標を指定します。
bezierVertex()の構文は以下の通りです。
bezierVertex(x2, y2, x3, y3, x4, y4)x2, y2に 最初の制御点のx,y座標、 x3, y3に 2つ目の制御点のx,y座標、 x4, y4に 最後の制御点のx,y座標 を指定します。
p5.js Reference: bezierVertex()
https://p5js.org/reference/#/p5/bezierVertex
- endShape()
endShape()で複雑な図形を描画を終了します。
endShape()で、beginShape()の呼び出し以降に定義された図形が画像バッファーに書き込まれ、形状を閉じます。endShape()の構文は以下の通りです。
endShape([mode])modeに CLOSE を使用して形状を閉じます。
p5.js Reference: endShape()
https://p5js.org/reference/#/p5/endShape3-7. 星柄
p5.jsを使用して、星柄を描きます。
3-7-1. サンプル
See the Pen p5.js_Star Pattern by Haruka Ogawa (@haruka0121) on CodePen.
3-7-2. 解説
以下に、星柄を描くための sketch.jsの内容を示します。
sketch.jsfunction setup() { createCanvas(800, 500); //サイズ background('#0000FF'); //背景色: 青色(#0000FF) } function draw() { let size=2; //星のサイズ let space=24; //星の間隔 for(let x=0;x <= width;x+=space*size){ for(let y=0;y <= height;y+=space*size){ noStroke(); //ストローク無効化 fill('#FFFF00'); //図形の塗り潰し:黄色(#FFFF00) star(x, y, 3*size, 8*size, 5); //星描画・・・,角の数:5 } } } function star(x, y, radius1, radius2, points) { let angle = TWO_PI / points; //points: 5 let halfAngle = angle / 2.0; let n = 175; beginShape(); //星描画開始 for (let a = -n; a < TWO_PI-n; a += angle) { let sx1 = x + cos(a) * radius2; let sy1 = y + sin(a) * radius2; vertex(sx1, sy1); //星の頂点座標:(sx1,sy1) let sx2 = x + cos(a + halfAngle) * radius1; let sy2 = y + sin(a + halfAngle) * radius1; vertex(sx2, sy2); //星の頂点座標:(sx2,sy2) } endShape(CLOSE); //星描画終了 }・setup関数内 記述
setup()には、サイズ 800px × 500px、背景色 青(#0000FF)の 描画領域を設定します。
function setup() { createCanvas(800, 500); //サイズ background('#0000FF'); //背景色: 青色(#0000FF) }・ draw関数内 記述
draw()には、星柄を描くための処理を記述します。
function draw() { let size=2; //星のサイズ let space=24; //星の間隔 for(let x=0;x <= width;x+=space*size){ for(let y=0;y <= height;y+=space*size){ noStroke(); //ストローク無効化 fill('#FFFF00'); //図形の塗り潰し:黄色(#FFFF00) star(x, y, 3*size, 8*size, 5); //星描画・・・,角の数:5 } } }使用した関数は、以下の通りです。
関数 説明 noStroke() ストロークの描画を無効にする。 fill() 図形を塗りつぶす色を設定する。 star() 星を描画する。draw() の後で star() の処理内容を記述する。
- noStroke()
noStroke()でストロークの描画を無効にすることができます。
noStroke()の構文は以下の通りです。
noStroke()p5.js Reference: noStroke()
https://p5js.org/reference/#/p5/noStroke
- fill()
fill()で図形を塗りつぶす色を設定することができます。
fill()の構文は以下の通りです。
fill(value)p5.js Reference: fill()
https://p5js.org/reference/#/p5/fill
- star()
星を描画するstar()を、この後 作成します。
・ star関数内 記述
star()には、星を描くための処理を記述します。
p5.js examples: Star
https://p5js.org/examples/form-star.htmlfunction star(x, y, radius1, radius2, points) { let angle = TWO_PI / points; //points: 5 let halfAngle = angle / 2.0; let n = 175; beginShape(); //星描画開始 for (let a = -n; a < TWO_PI-n; a += angle) { let sx1 = x + cos(a) * radius2; let sy1 = y + sin(a) * radius2; vertex(sx1, sy1); //頂点座標 let sx2 = x + cos(a + halfAngle) * radius1; let sy2 = y + sin(a + halfAngle) * radius1; vertex(sx2, sy2); //頂点座標 } endShape(CLOSE); //星描画終了 }使用した関数は、以下の通りです。
関数 説明 beginShape() 複雑な図形描画の開始。 vertex() 図形の頂点座標を指定する。beginShape()およびendShape()関数内で使用できる。 endShape() 複雑な図形描画の終了。
- beginShape()
beginShape() と endShape() を使用して、複雑な図形を描画することができます。
beginShape() は図形の頂点の記録を開始します。beginShape()の構文は以下の通りです。
beginShape()p5.js Reference: beginShape()
https://p5js.org/reference/#/p5/beginShape
- vertex()
vertex()は、beginShape()およびendShape()関数内で、図形の頂点座標を指定することができます。
vertex()の構文は以下の通りです。
vertex(x, y)xに頂点のx座標、yに頂点のy座標を指定します。
p5.js Reference: vertex()
https://p5js.org/reference/#/p5/vertex
- endShape()
endShape()で複雑な図形を描画を終了します。
endShape()で、beginShape()の呼び出し以降に定義された図形が画像バッファーに書き込まれ、形状を閉じます。endShape()の構文は以下の通りです。
endShape([mode])modeにCLOSEを使用して形状を閉じます。
p5.js Reference: endShape()
https://p5js.org/reference/#/p5/endShape4. おわりに
今回は p5.js を使用して ハート柄・星柄を描画しました。
前回より 少し複雑な描画となりましたが、
使い方次第で 様々な図形を描画できて、自由度の高さを感じました。参考情報
p5.js 公式サイト
https://p5js.org/p5.js Web Editor: Heart shape
https://editor.p5js.org/Mithru/sketches/Hk1N1mMQgp5.js examples: Star
https://p5js.org/examples/form-star.html
- 投稿日:2021-01-27T18:07:47+09:00
フォームブリッジでカスタムバリデーション作成方法
はじめに
フォームブリッジでカスタムバリデーションを実装する方法を紹介します。
フォームブリッジはwebフォームを作成し、入力された情報を自動でkintoneにデータ保存出来るサービスです。
詳しくはこちら!https://kintone-sol.cybozu.co.jp/integrate/toyokumo006.html
JavaScriptへの記述方法
フィールドへバリデーションを追加する記述
その1
state.fields[0].validations.push({ params: [data], rule: 'sample_validation' });
- fields[0]で追加したいフィールドを特定し、バリデーションを追加
- フィールドの順番が今後変化する場合には使用せず、その2で紹介する方法がおすすめ
- paramsにはバリデーションチェックするために必要な値を格納する
- ruleにはバリデーションの名前を自分で付ける
その2
state.fields.find(({code}) => code === "code名").validations.push({ params: [data], rule: 'sample_validation' });
- fields.find(({code}) => code === "code名")でフィールドの中から追加したいフィールドのコード名を指定し、バリデーションを追加
バリデージョンを実行したい場所に追加する
画面ロード時
fb.events.form.created.push(function (state) { state.fields.find(({code}) => code === "code名").validations.push({ params: [data], rule: 'sample_validation' }); return state; });
- 画面ロード時にバリデーションを追加するため、ユーザの操作によってparamsのデータが変化しない場合に使用すると良い
入力イベント時
fb.events.fields.code名.changed = [function (state) { state.fields.find(({code}) => code === "code名").validations.push({ params: [data], rule: 'sample_validation' }); return state; }];
- 入力イベント時に発生するため、ユーザの操作によってparamsのデータが変化する場合に使用すると良い
バリデーションの記述方法
fb.addValidators = function (state) { return { sample_validation: { getMessage: function (fieldCode, params) { return 'バリデーションエラーのメッセージ'; }, validate: function (value, params) { //処理の中身を記述 return false; } } } };
- fb.addValidators = function (state) {}の中にバリデーションの処理を追加していく。※複数のバリデーションを記述しても可
- sample_validationが自分がつけたバリデーションの名前
- getMessage:のreturnに表示させたいエラーメッセージを記述
- validate:にバリデーションの処理の中身を記述。returnがfalseの場合にエラーとなる。
応用編
kViewerを利用し、kintoneアプリのデータを呼び出してそのデータを元にバリデーションを実行する方法を紹介します。
kViewerとはkintone内の情報を、ライセンスを保有していない閲覧者・外部の方に公開するためのサービスです
詳しくはこちら!
https://kintone-sol.cybozu.co.jp/integrate/toyokumo003.html?_ga=2.47974183.1487919851.1611485452-1158750218.1608367703ここでは番号が重複している場合にエラーとするバリデーションを紹介します
let number = ""; // Kviewerで設定されたURLを記述する kv_data = "https//...."; function getSampleAllData(number) { const params = { additionalFilters:[ // 入力した番号に一致するものを取得する { width: "and", field: "番号", sign: "=", value: number } ] }; const url_sample = kViewr.generateUrl(kv_data, params); return $j.ajax({ url: url_sample }); }; fb.events.fields.番号.changed = [function (state) { state.fields.find(({code}) => code === "番号").validations.push({ params: [getSampleAllData(record.["番号"].value)], rule: 'sample_validation' }); return state; }]; fb.addValidators = function (state) { return { sample_validation: { getMessage: function (fieldCode, params) { return '番号が重複しています。'; }, validate: function (value, params) { if (params[0].totalCount > 0) { return false; } else { return true; } } } } };
- 投稿日:2021-01-27T17:51:20+09:00
Google Cloud Speech API を使って話者分離を行い文字起こしする
はじめに
wavファイルから話者分離して文字起こしをする方法をまとめます.色々な記事で紹介して頂いていて参考にさせていただいていたのですが上手く行かないところが多かったのでこちらでまとめさせていただきます.
参照した記事
- https://qiita.com/rxoxixyxd/items/ff0c44745db834123922
- 全体の流れについて
- https://cloud.google.com/speech-to-text/docs/multiple-voices?hl=ja#speech_transcribe_diarization_gcs_beta-nodejs
- Googleのガイド
- 開発したソースコードはほんの少し変更したのみです.
- 「Google Cloud Storage バケットの使用」に書いてある「Node.js」のコードを使わせていただきました.
- https://cloud.google.com/speech-to-text/docs/async-recognize?hl=ja
- 1分以上のwavファイルを文字起こしすることに関して
- 30分などの数十分単位の音声ファイルを文字起こしするので上記のリンクから少しだけ変更を加えて長時間の音声ファイルにも対応できるようにしました.
- https://stackoverflow.com/questions/60433604/syntaxerror-await-is-only-valid-in-async-function-in-google-cloud-speech-to-tex
- SyntaxError: await is only valid in async functionというエラーに関して
- https://cloud.google.com/speech-to-text/docs/transcription-model?hl=ja
- configのmodelに関して
- 音声文字変換モデルが4つほどあるようです.本当は'phone_call'モデルを使いたいところだったのですが'phone_call'と'video'は'ja-JP'対応していないようなので'default'か'command_and_search'で動かしました.
手順
- 次のコマンドでライブラリをインストール
npm install --save @google-cloud/speech
- exportでjsonファイルをexportする際に次のコマンドが必要
- これ毎回やらないといけないかも知れません。
export GOOGLE_APPLICATION_CREDENTIALS="[JSONファイルの絶対パス]"
- JSONファイルの絶対パスがわからないときは次のコマンドを実行
- filename.jsonにはJSONファイルのファイル名を記載
- たぶん結果は/home/アカウント名/jsonファイル名とかになると思います。
find / -name filename -type f
- 次のコマンドを実行
nano diarization.js
- diarization.jsの中に次のコードを書き込む
diarization.js// Imports the Google Cloud client library const speech = require('@google-cloud/speech').v1p1beta1; // Creates a client const client = new speech.SpeechClient(); /** * TODO(developer): Uncomment the following line before running the sample. */ // const uri = path to GCS audio file e.g. `gs:/bucket/audio.wav`; const config = { encoding: 'LINEAR16', sampleRateHertz: 44100, languageCode: 'ja-JP', enableSpeakerDiarization: true, diarizationSpeakerCount: 3, model: 'command_and_search', //ここが'phone_call'とかに変えたいと箇所 }; const audio = { uri: 'gs://bucket/filename.wav', //ここはそれぞれの動作環境で変えてください }; const request = { config: config, audio: audio, }; async function main() { const [operation] = await client.longRunningRecognize(request); const [response] = await operation.promise(); // const [response] = await client.recognize(request); const transcription = response.results .map(result => result.alternatives[0].transcript) .join('\n'); console.log(`Transcription: ${transcription}`); console.log('Speaker Diarization:'); const result = response.results[response.results.length - 1]; const wordsInfo = result.alternatives[0].words; // Note: The transcript within each result is separate and sequential per result. // However, the words list within an alternative includes all the words // from all the results thus far. Thus, to get all the words with speaker // tags, you only have to take the words list from the last result: wordsInfo.forEach(a => console.log(` word: ${a.word}, speakerTag: ${a.speakerTag}`) ); } main()
- wavファイルのプロパティ->詳細からビットレートを確認
- こちらのサイトを参考にしてビット数とsample rate hertzを確認
- こちらのサイトを通じてchannelをmonoに変更
- ビットはプロパティで確認したビット数
- 周波数もプロパティで確認したsample rate hertz
- チャンネルはモノラル(1チャンネル)
- バケットを作成
- 音声ファイルをアップロート
- バケットの権限を編集->メンバーを追加
- サービスアカウント名([]@[].iam.gserviceaccount.comという名前のやつ)
- ロールはCloud Storageレガシー->Storageレガシーバケットオーナー
- 音声ファイル->権限を編集->エントリを追加
- エンティティはUser
- 名前はサービスアカウント名([]@[].iam.gserviceaccount.comという名前のやつ)
- アクセスはOwner
- 次のコマンドを実行
node diarization.js
- terminal上に書き起こされた文字列たちが表示されると思います.
他にやってみたけど諦めたこと
Java
諦めた原因
Node.jsじゃなくて最初はJavaでやってみようとしました.しかし次のエラーが出て断念しました.
error: package com.google.cloud.speech.v1 does not existどこまでやって諦めたか
pom.xmlというファイルの中身を書き換えると良いようなのでやってみたのですが結局上手くできませんでした.もしJavaでやろうとしてお考えたの方がいらっしゃいましたらすみませんが私の記事は役に立たないかなと思います.すみません泣
手順
- 次のコマンドでpom.xmlというファイルの絶対パスを取得
find / -name pom.xml -type f
- 「find: ~」から始まって「: Permission denied」で終わる文章が何行も出てきて最後の行に次の文章が得られました.
/google/devshell/editor/language_servers/java/scripts/pom.xml
- 次のコマンドで該当の階層まで移ってpom.xmlを編集する
cd /google/devshell/editor/language_servers/java/scriptsnano pom.xml
- で囲われている直下にタブたちを追記しました.
- こちらを参考を参考にしました.
- 同じエラーが出た.
IBM Cloud
IBMさんもクラウドを提供してくださっていたので利用させていただきました.個人的な感想ですがUIがめちゃめちゃ整理されていたのでとんでもなく使いやすかったです.
しかし精度はあまり出ませんでした泣
私が使ったwavファイルの音声がぼそぼそしたものでしたし、ちゃんとしたマイクなどを使って音声を拾っていたわけではないので仕方ないかなって思いました.
https://speech-to-text-demo.ng.bluemix.net/おわりに
2020年の8月頃とかにやったことをまとめてみました.今と変わっている所もあるかも知れません.変わっていたら本当に申し訳ありません泣
音声書き起こしなどをやっていらっしゃる方がいたらどうぞ使っていってください.
- 投稿日:2021-01-27T17:40:01+09:00
Javascriptで入れ子の配列やオブジェクトをコピーする際の注意点
仕事でnode書いている時にオブジェクトの参照渡しで思わぬ挙動が起きることがよくありました。
参照渡しと値渡しの違いについては下の記事を参考にしてください。
今回は、オブジェクトを配列で持つ変数の注意点です。配列を代入ではなくコピーする
配列を複製してオリジナルとコピーした変数を使いたくなる場面が少なからずあると思います。
そんな時によくやってしまいがちなのが参照渡しです。
この場合、変数bの要素だけを変更したとしても、変数aまで変わってしまいます。const a = [1, 2, 3]; const b = a; console.log(a); // 1, 2, 3 console.log(b); // 1, 2, 3 b[0] = 4; console.log(a); // 4, 2, 3 console.log(b); // 4, 2, 3aまで変わったらオリジナルじゃないじゃん!って嘆くことってありますよね。(自分はよくやらかしてました)
よく解決策として上げられるのが[concat]という関数です。(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/concat)
他にも方法があると思いますが、筆者はこれをよく使うので今回はconcatにだけ着目します。concat関数は元の配列に対して引数の要素を付け加える関数ですが、新しく配列を生成するのでオリジナルの変数とは参照先が異なる値を持つことになります。
そのため、コピー先の要素を変更してもオリジナルの変数が変更されることはありません。const a = [1, 2, 3]; const b = a.concat(); console.log(a); // 1, 2, 3 console.log(b); // 1, 2, 3 b[0] = 4; console.log(a); // 1, 2, 3 console.log(b); // 4, 2, 3これが配列の代入ではなくコピーです。
オブジェクトの配列をconcatしたらどうなるか
表形式でデータを表示する場合など、オブジェクトを配列の形式で持つことがあると思います。
const a = [{"key1" : "value1"}, {"key2" : "value2"}]それではいつものようにこいつをconcatでコピーして中のオブジェクトを更新してみましょう。
const a = [{"key1" : "value1"}, {"key2" : "value2"}]; const b = a.concat(); console.log(a); // [ { key1: 'value1' }, { key2: 'value2' } ] console.log(b); // [ { key1: 'value1' }, { key2: 'value2' } ] b[0]["key1"] = "value3"; console.log(a); // [ { key1: 'value3' }, { key2: 'value2' } ] console.log(b); // [ { key1: 'value3' }, { key2: 'value2' } ]あれ?変数aも変わってるやん・・・コピーしたはずなのに・・・
なんてことがあったので解決策調べてまとめて、今回の記事を作成しました(前置きが長い)中のオブジェクトもコピーしよう
concatで配列をコピーしたところで、中のオブジェクトのキーの参照先はオリジナルとコピーで同じものになる、つまり更新すれば片方も変わることになります。
それなら中のオブジェクトもコピーしてしまおう!という発想で解決しました。const a = [{"key1" : "value1"}, {"key2" : "value2"}]; const b = a.map((obj) => Object.assign({}, obj)); console.log(a); // [ { key1: 'value1' }, { key2: 'value2' } ] console.log(b); // [ { key1: 'value1' }, { key2: 'value2' } ] b[0]["key1"] = "value3"; console.log(a); // [ { key1: 'value1' }, { key2: 'value2' } ] console.log(b); // [ { key1: 'value3' }, { key2: 'value2' } ]assign関数はオブジェクトをマージして新しくオブジェクトを作ってくれる関数です。
こんな面倒なことしなくてもいい感じに配列コピーしてくれよ、って思いますがプログラムは思い通りにいかないもんですね。
しかもこれ、オブジェクトの中が配列やオブジェクトになるとさらにconcatやらassignやらやらないといけなくなることに後々気づきました。おわりに
配列やオブジェクトをコピーして使う時には、参照渡しや値渡しを意識しながら使う必要があります。
Javascriptに限らず様々な言語でも同じ事象は発生するので、今回のような事象を機にプログラミング言語を詳しく知っていくことも大事かなと思います。
ちなみに記事を書く過程で色々調べていたら、今回のように入れ子になった配列やオブジェクトをコピーすることをディープコピーということが分かりました。
しかもディープコピー用のライブラリとかもあるらしいので、先人たちって偉大だなと痛感しました。(というか早く知りたかった!)
[JavaScript]色々なディープコピー初投稿につき稚拙なところはご容赦ください。
最後まで閲覧いただきありがとうございました。
- 投稿日:2021-01-27T17:18:49+09:00
Electronアプリの作り方
はじめに
Electronという、ChromiumとNode.jsを使ったWeb技術でデスクトップアプリを作ることができるフレームワークを使います。
最初にやること
アプリを作成するためのフォルダを作る。
今回は、Electronとしました。$ cd フォルダのパスとしてフォルダを指定する。
package.jsonを作成する
$ npm init -ypackage.json{ "name": "Electron", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }このようなファイルが作成される。
アプリのバージョンを変更するには、"version": "1.0.0"を変更する。Electronをインストールする
$ npm i -D electron結構待たされる。
srcフォルダ等作成
srcフォルダを作り、その中に
- index.html
- main.js
- package.json
を作成。
index.htmlはご自由に書いてください。
今回はHello worldを表示します。index.html<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Electron</title> </head> <body> <h1>Hello world</h1> </body> </html>main.jsconst { app, Menu, BrowserWindow } = require('electron'); const path = require('path'); const url = require('url'); let mainWindow; function createWindow() { mainWindow = new BrowserWindow({width: 1200, height: 675, 'icon': __dirname + 'favicon.ico'}) mainWindow.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true })); mainWindow.on('closed', () => { mainWindow = null; }); } app.on('ready', createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (mainWindow === null) { createWindow(); } });
'icon': __dirname + 'favicon.ico'でアイコンを指定している。なくても良い。package.json{ "main": "main.js" }main.jsを指定
試しに起動してみる
$ npx electron srcHello worldが表示されました。
パッケージング
electron-packagerを使ってパッケージングする
electron-packagerのインストール
$ npm i -D electron-packagerそれでは、パッケージングしていきます。
windows向けです。$ npx electron-packager src electron --platform=win32 --arch=x64 --overwrite --icon=src/favicon.icoここでもアイコンを指定しています。
Electronのデザイン
全画面&タイトル、メニューバーなし
main.jsmainWindow = new BrowserWindow({kiosk: true, 'fullscreen': true, 'frame': false});main.jsのnew BrowserWindowを指定しているところに追加する
展示用などにおすすめ。
Ctrl+Wでアプリがシャットダウンされる。メニューバーなし
main.jsmainWindow.setMenu(null);とてもシンプルで良い。
パッケージングを楽に
package.json"scripts": { "start": "electron ./src", "macos": "electron-packager ./src electron --platform=darwin --arch=x64 --overwrite --icon=src/favicon.ico", "windows": "electron-packager ./src electron --platform=win32 --arch=x64 --overwrite --icon=src/favicon.ico" }と、追加しておきます。
このとき、忘れずに"start"の前に,を追加してください。$ npm run windowsとするとかんたんにパッケージングできます。
windowsをmacosに変えるとMacOS向けにパッケージングされます。まとめ
Web技術でアプリを作ることができました。
サクっとアプリが作れるいい時代ですね。参考
- 投稿日:2021-01-27T17:13:43+09:00
【初心者でもわかる】アラートや確認ダイアログを画面中央に表示する方法
どうも7noteです。アラートなどの警告ボックスを画面中央に表示させます。
javascriptのalert等は表示位置を変えることができないので1からオリジナルで作ります。
ボタンを押した後の処理は書いてませんので利用目的に合わせて改良してお使いください。確認してくるボックスを画面中央に出すソースのサンプル
※jQueryをちょっとだけ使ってます。jQueryって何?という方はこちら。
index.html<div id="overflow"> <div class="conf"> <p>本当に決定してもいいですか?</p> <div class="btns"><input type="button" value="キャンセル" onClick="cansel();"> <input type="button" value="オッケー" class="ok" onClick="next();"></div> </div> </div> <p>これでいいですか?</p> <input type="button" value="決定" onClick="check();">style.css#overflow { width: 100vw; /* 横幅を画面いっぱいにする */ height: 100vh; /* 高さを画面いっぱいにする */ background-color: rgba(0,0,0,0.2); /* 背景を半透明の黒い背景にする */ position: absolute; /* 相対位置に指定 */ z-index: 10; /* ウィンドウの全面に表示 */ display: none; /* 初期は非表示 */ } #overflow .conf { background: #FFF; /* 背景を白色に指定 */ padding: 20px; /* 余白を20pxに指定 */ position: absolute; /* 装置位置に指定 */ top: 50%; /* 上から50%の位置に配置 */ left: 50%; /* 左から50%の位置に配置 */ transform: translate(-50%,-50%); /* コンテンツの半分だけ位置を戻して上下左右中央に配置 */ } .btns { text-align: right; /* 要素を右寄せにする */ } .btns .ok { /* okボタンの装飾を変えるなら書く */ }script.jsfunction check(){ $("#overflow").show(); } function cansel(){ $("#overflow").hide(); // 確認ボックスを消す } function next(){ $("#overflow").hide(); // ok後の処理を書く }結果
解説
標準で出すことのできる
alert()やconfirm()は表示位置を変えることができません。
なので、新しくボックスを作り、ボタンを並べてそれぞれ個別に処理を書こうという発想です。まとめ
今回装飾は最低限にしていますので、自由に装飾してください。
もちろんアラートのボックスを上下中央にしなくても好きな位置に持ってきたり、出し方を工夫したりしてもいいかなと思います。おそまつ!
~ Qiitaで毎日投稿中!! ~
【初心者向け】WEB制作のちょいテク詰め合わせ
- 投稿日:2021-01-27T17:10:52+09:00
bulletml.jsの研究 その6
概要
bulletml.jsの研究です。
技を調査。n-way
<bulletml> <action label="top"> <repeat> <times>22</times> <action> <fire> <direction type="aim">-30</direction> <bullet> <action> <changeDirection> <direction type="sequence">0</direction> <term>20</term> </changeDirection> </action> </bullet> </fire> <repeat> <times>4</times> <action> <fire> <direction type="sequence">15</direction> <bullet> <action> <changeDirection> <direction type="sequence">0</direction> <term>20</term> </changeDirection> </action> </bullet> </fire> <wait>3</wait> </action> </repeat> <wait>30</wait> </action> </repeat> </action> </bulletml>一度に複数の方向へ等間隔に発射する攻撃です。
発射弾数によって5way、7wayなどと呼びます。
間隔、発射弾数、発射方向の自機依存/非依存や偶数/奇数などでバリエーションを広げていきます。成果物
https://embed.plnkr.co/plunk/lx80g18Lp4lAUMAb
以上。
- 投稿日:2021-01-27T16:46:37+09:00
JavaScript復習⑥
JavaScript復習⑤からの続きです。
関数の呼び出し方と渡し方
JavaScriptファイルprintWanko() //関数が呼び出される printWanko //関数の定義そのもの'use strict'
JavaScriptコードを記述する際には、先頭に'use strict'; と記述する
バックスラッシュ
JavaScriptファイルconsole.log('it's me!'); // これだとit'sの'が終端記号として認識され、エラーが出てしまう console.log("it's me!") //ダブルクォーテーションで表記する //もしくは console.log('it\'s me!') //バックスラッシュを用いて表記するバックスラッシュを用いた他の記法として、
\n ・・・ 改行 \t ・・・ タブ
などが挙げられる。べき乗
JavaScriptファイルconsole.log(10 ** 3); // **はべき乗を表すコンソール1,000JavaScriptのデータ型
・文字列・・・ String
・数値・・・ Number
・Undefined
・Null
・真偽値・・・ Boolean(true or false)
・オブジェクト ・・・Object (例) {a: 3, b: 5}typeof
JavaScriptで値の方がどの種類の方なのか調べられる演算子
parseInt
parseIntで、数値に関して、文字列の連結ではなく、足し算にしたい場合に、
数値を文字列から整数値に変換する方法JavaScriptファイルconsole.log('5' + 3); // このままだと53と出力される console.log(parseInt('5', 10)+ 3); // このように表記すると8と出力される。10は10進数を意味する単一の値の真偽値での評価
false ・・・ 0, null, undefined, ' '(空文字列), false
true ・・・ 上記以外
→値をtrue, falseで評価するには、Boolean()という命令を用いる条件演算子
JavaScriptファイル// 条件演算子 条件式 ? trueの処理 : falseの処理JavaScript復習以上
- 投稿日:2021-01-27T16:46:11+09:00
JavaScript復習⑤
JavaScript復習④からの続きです。
入力値を使う
JavaScriptファイルimport readlineSync from "readline-sync"; const name= readlineSync.question("名前を入力してください:"); console.log(`${name}が入力されました);コンソール名前を入力してください: タロウ タロウと入力されました整数の入力
JavaScriptファイルconst name = readlineSync.question("名前を入力してください:"); const age = readlineSync.questionInt("年齢を入力してください:"); // 整数を入力させる場合はquestionではなく、questionIntを使うpushメソッド
JavaScriptファイルconst numbers = [1,2,3]; console.log(numbers); numbers.push(4); console.log(numbers);コンソール[1,2,3] [1,2,3,4]forEachメソッド
JavaScriptファイルconst numbers = [1,2,3]; numbers.forEach ((number)=> {console.log(number); } ); // コールバック関数の形になっているコンソール1 2 3findメソッド
JavaScriptファイルconst numbers = [1,3,5,7]; const foundNumber = numbers.find ((number) =>{ return number > 3; }); console.log(foundNumber);コンソール5 //条件に合う最初の要素だけが取り出される配列の要素がオブジェクトの場合もfindメソッドが使える
JavaScriptファイルconst characters = [ {id: 1, name: "たろう"}, {id: 2, name: "はなこ"} ]; const foundCharacter = characters.find ((character)=>{ return character.id === 1; }); console.log(foundCharacter);コンソール{id: 1, name: "たろう"}filterメソッド
JavaScriptファイルconst numbers = [1,3,5,7]; const filteredNumbers = numbers.filter ((number)=>{ return > 3; }); console.log(filteredNumbers);コンソール[5,7] //条件に合う要素が全て取り出される配列の要素がオブジェクトの場合もfilterメソッドが使える
JavaScriptファイルconst characters = [ {name: "たろう", age: 20}, {name: "はなこ", age: 8}, {name: "けんた", age: 5} ]; const filteredCharacters = characters.filter ((character)=>{ return character.age > 7; }); console.log(filteredCharacters)コンソール[ {name: "たろう", age: 20}, {name: "はなこ", age: 8} ]mapメソッド
mapメソッド・・・ 配列内の全ての要素に処理を行い、その戻り値から新しい配列を作成するメソッド
JavaScriptファイルconst numbers = [1,2,3]; const doubledNumbers = numbers.map ((number)=> { return number * 2; }); console.log(doubledNumbers);コンソール[2,4,6] //配列numbersの全ての数値が2倍され、新しい配列が作成された配列の要素がオブジェクトの場合もmapメソッドが使える
JavaScriptファイルconst names = [ {familyName: "Tanaka", lastName: "Taro"}, {familyName: "Suzuki", lastName: "Hanako"} ]; const fullNames = names.map ((name)=>{ return name.familyName + name.lastName; }); console.log(fullNames);コンソール["TanakaTaro", "SuzukiHanako"]続きはJavaScript復習⑥へ
- 投稿日:2021-01-27T16:32:31+09:00
bulletml.jsの研究 その5
概要
bulletml.jsの研究です。
技を調査。固定方向弾
<bulletml> <action label="top"> <repeat> <times>222</times> <action> <fire> <direction type="sequence">23</direction> <bullet> <action> <wait>20 + $rand * 50</wait> <changeDirection> <direction type="absolute">180</direction> <term>20</term> </changeDirection> </action> </bullet> </fire> <wait>3</wait> </action> </repeat> </action> </bulletml> </textarea>自機狙いに対し、自機の位置に依存しない攻撃です。
単発ではあまり意味をなしませんが、規則的にたくさんの固定方向弾を配置することで、障害物として機能させることも出来ます。成果物
https://embed.plnkr.co/plunk/mAM1UmYbTZBVempo
以上。
- 投稿日:2021-01-27T16:22:21+09:00
子供の遊び場共有サービス「Crayfisher」
Ruby on Railsで子供の遊び場共有サービスを開発しました。
使用した技術に関する記事を後学のため&備忘録として書き残しておきます。
_________以下概要_________
Crayfisherは子供の遊び場スポットを共有するサービスです。 ザリガニ釣りスポット、クワガタの取れる木、トカゲがいる場所、ネットでは出てこない遊び場スポットを知りたい時、是非Crayfisherを是非ご利用ください。
また、子供の頃よく行っていた遊び場があれば全国のお母さん、お父さんたちのために是非共有してください。
url : https://crayfisher.herokuapp.com/
ログイン用
メールアドレス:example@example.com
パスワード:foobar■ 実装機能
* 記事投稿機能(位置情報、コメント)
* 地名による地図検索機能
* 認証機能(devise)
* ページネーション機能
* アプリケーション内で使用している技術
* Rspecを使用した自動テスト
* Ransackを利用した検索機能
* rubocopを使用した静的コード解析ツール
* CircleCIによる継続的インテグレーション
* Dockerによる環境構築
* Googlemap API
* S3を利用したクラウドストレージ
* gem "bullet"を利用したN+1問題の検出・解決
* sass, slimを使用した記述■ 環境
* ホストOS : MacOS
* データベース:Postgresql
* 言語 : HTML CSS(SCSS) JavaScript Ruby SQL
* フレームワーク : Ruby on Rails
* CSSフレームワーク : bootstrap
* JSライブラリ : jQuery
* インフラ : heroku Docker AWS S3
* テストフレームワーク : RSpec
* その他ツールなど : Git Github Rubocop CircleCI
*
- 投稿日:2021-01-27T15:11:44+09:00
DOMContentLoadedについて
※ただのメモです
javascriptとかで使われる「DOMContentLoaded」と言うイベントは、最初の HTML 文書の読み込みと解析が完了したとき、スタイルシート、画像、サブフレームの読み込みが完了するのを待たずに発生するやつ
つまり画面をロードされる前に実行されるイベントになる。
以下の記述はHTML文書の読み込みと解析が完了したとき「123」の数値をコンソールに出力する簡単なコードdocument.addEventListener('DOMContentLoaded',function (){ console.log(123); });
これと似たやつが「load」になる。以下コード
window.addEventListener('load',function (){ console.log(123); });参考記事
https://developer.mozilla.org/ja/docs/Web/API/Window/DOMContentLoaded_event
- 投稿日:2021-01-27T14:50:34+09:00
Vuejsのコンポーネントについて
HTMLテンプレートと機能などをまとめることができる機能としてコンポーネントがあります。
今回は、コンポーネントの基本的な機能についてまとめてみたいと思います。コンポーネントを使う上で基本的な考え方
コンポーネント化することで何がメリットかというと
・機能ごとに区別して作成が可能
・再利用可能になり保守性が高めることができる
ことがあげられます。そして、
コンポーネントには"使う側(親)”と"使われる側(子)"と言う関係になります。
この関係を抑えることでコードの記載する内容も変わってきますので注意しましょう。グローバルコンポーネントとローカルコンポーネント
コンポーネントには2種類あります。
グローバルとローカルのコンポーネントです。
・Vueのインスタンスを複数作成した際にどのインスタンスでも適用させたい場合にはグローバルコンポーネントを使用します。
・特定のVueインスタンス内で使用したい場合にはローカルコンポーネントを使用します。定義する場合には下記のようになります。
記載方法の違いと言えばcreateApp({})で定義するか、.componentで宣言するかの違いです。グローバルコンポーネント
Vue.createApp({}).component('mydata',{ data:function(){ return{ title:'', } }, template: `<input type="text" v-model="title" />`, })ローカルコンポーネント
Vue.createApp({ component: { 'mydata': { data: function () { return { title: '', } }, template: `<input type="text" v-model="title" />`, }, }, }).mount('#app')一点注意点としては、グローバルコンポーネントを利用する場合にはJavaScriptファイルが上から読み込まれてしまうので、適用したいVueインスタンスよりも前に記述することが必要です。
Vue.component('sample1', { data() { return { testms: 'hello!' } }, template: '<div>{{ testms }}</div>' }) new Vue({ el: '#app' }) //上記でVueインスタンスが定義されたため、ここから下のコンポーネントは読み込まれない。 Vue.component('sample2', { data() { return { testms2: 'bye!' } }, template: '<div>{{ tsetms2 }}</div>' })参考:VueのComponent(コンポーネント)の書き方・使い方について解説
コンポーネント定義の内容について
コンポーネントの定義については、2つポイントを説明します。
sample.jsVue.createApp({ component: { 'mydata': { data: function () { return { title: '', } }, template: `<input type="text" v-model="title" />`, }, }, }).mount('#app')・dataプロパティの取り扱い
コンポーネント内で使用したいdataプロパティについては、定義する際にオブジェクトを返す関数である必要があります。
data: function () { //function定義 return { //return title: '', } },・templeteの取り扱い
コンポーネントのHTMLを定義するためにはtempleteを定義する必要があります。
template: `<input type="text" v-model="title" />`,ただ、現実問題としてコンポーネントが複雑になると文字列として定義するには可読性が低くなってしまいます。
そのために、templeteの内容をHTMLへ記載する方法があります。html<div id="app"> <mydata></mydata> </div> <script type="text/x-template" id="mydata-template"> <input type="text" v-model="title" /> </script>javascripttemplate: '#mydata-template',template内の要素を下記のようにscriptタグ内で定義することhtmlに記載することが可能です。
<script type="text/x-template" id="~~~~"> //templeteの内容 </script>後は、htmlのidとJavaScriptの'#~'で紐づけることで、コンポーネントのtemplete部分の可読性が上がり、記載も簡単になります。
コンポーネント自体が冗長になった時には。。
上記のsample.jsファイルのコンポーネントが冗長になり、可読性が低いと感じる時にはコンポーネントを切り離して,constで宣言してあげることで回避するのも一つの手です。
sample.js//コンポーネントを切り離す const mydataobj = { data: function () { return { title: '', } }, template: '#mydata-template', } Vue.createApp({ component: { 'mydata': mydataobj }, }).mount('#app')と言うような形でコンポーネントの概要についてまとめてみました。
コンポーネントが理解できれば後は値の受け渡しが必要ですよね。
近日中に追記したいと思います。
近日中に追記予定
- 投稿日:2021-01-27T14:29:38+09:00
JavaScript復習④
JavaScript復習③からの続きです。
コンストラクタのオーバーライド
JavaScriptファイルclass 子クラス extends 親クラス { constructor() { super() //1行目にsuper()の記述が必要 // 子クラスのコンストラクタの処理 } }export
JavaScriptファイルclass Animal { . . } export default Animal; //Animalクラスを他のファイルでも使用できるようにする設定import
JavaScriptファイルimport Animal from "./[Animalクラスを定義したコードを記述しているファイル名](.jsは省略できる)" // ↑先頭に記述する値のエクスポート
sample1.jsconst text = "Hello World"; export default text;sample2.jsconst text from "./sample1"; console.log(text);コンソールHello Worldデフォルトエクスポート
デフォルトエクスポートは1ファイル1つの値のみ使える。そのファイルがインポートされると自動的に、
「export default 値」の値がインポートされる。
→エクスポート時の値の名前と、インポート時の値の名前に違いがあっても問題ない名前付きエクスポート
dogData.jsconst dog1 = new Dog("タロウ", 20, "柴犬"); export {dog1};script.jsimport {dog1} from "./dogData"; dog1.info();名前付きエクスポートはデフォルトエクスポートと異なり、
複数の定数やクラスを指定してエクスポートすることができるdogData.jsconst dog1 = new Dog("タロウ", 20, "柴犬"); const dog2 = new Dog("ハナコ", 8, "ブルドッグ"); export {dog1, dog2};script.jsimport {dog1, dog2} from "./dogData";相対パス
同じディレクトリのファイル指定
JavaScriptファイルimport {dog1, dog2} from "./dogData";異なるディレクトリのファイル指定
JavaScriptファイルimport {dog1, dog2} from "./data/dogData"; // ./dataで同じディレクトリ内のdataディレクトリに移動、 /dogDataでdogData.jsを指定一つ上の階層に戻る
JavaScriptファイルimport Dog from "../class/dog"; // ..で一つ上の階層に移動、 /classでclassディレクトリに移動、 /dogでdog.jsを指定パッケージのimport
JavaScriptファイルimport 定数名 from "パッケージ名";chalkパッケージの使い方
JavaScriptファイルimport chalk from "chalk"; console.log(chalk.yellow("Hello World")); console.log(chalk.bgCyan("Hello World")); //文字列を囲むことができるreadline-syncの使い方
JavaScriptファイルimport readlineSync from "readline-sync"; readlineSync.question("名前を入力してください:");コンソール名前を入力してください: // 質問文が出力されると、一旦処理が止まり、 // コンソールに値が入力されると次の処理に進む続きはJavaScript復習⑤へ
- 投稿日:2021-01-27T14:28:58+09:00
JavaScript復習③
JavaScript復習②からの続きです。
様々な戻り値
JavaScriptファイルconst check = (number)=> { return number % 2 === 0; }; console.log(check(6)); console.log(check(7));コンソールtrue falseオブジェクトと関数
JavaScriptファイルconst user = { name: "たろう" greet: ()=> { console.log("こんにちは!"); } }; user.greet(); //関数の呼び出しコンソールこんにちは!インスタンス
JavaScriptファイルclass Animal { } const animal = new Animal(); console.log(animal);コンソールAnimal{ } //空のオブジェクトコンストラクタ
JavaScriptファイルclass Animal { constructor() { console.log("こんにちは!"); } } const animal1 = new Animal(); const animal2 = new Animal();コンソールこんにちは! こんにちは!インスタンスとプロパティ
JavaScriptファイルclass Animal { constructor() { this.name = "タロウ"; } } const animal = new Animal(); console.log(animal.name);コンソールタロウコンストラクタの引数
JavaScriptファイルclass Animal { constructor(name, age) { this.name = name; this.age = age; } } const.animal = new Animal("タロウ", 20);メソッド
JavaScriptファイルclass Animal {] constructor(name, age) { . . } info() { console.log(`名前は${this.name}です`); } } const animal = new Animal("タロウ", 20); animal.info();コンソール名前はタロウですメソッド内でメソッドを使う
JavaScriptファイルclass Animal { greet() { console.log("こんにちは"); } info() { this.greet(); //同じクラスのメソッドを実行 . . } }継承
JavaScriptファイル// Animalクラスを継承 class Dog extends Animal { }メソッドの戻り値
JavaScriptファイルclass Dog extends Animal { getHumanAge() { return this.age * 7; } } const dog = new Dog("タロウ", 20); const humanAge = dog.getHumanAge(); console.log(humanAge);コンソール140子クラスのメソッド
子クラスで定義した独自のメソッドは親クラスから呼び出すことはできない
オーバーライド
親クラスと同じ名前のメソッドを子クラスに定義すると、子クラスのメソッドが優先して使用される。
(子クラスのメソッドが親クラスのメソッドを上書きしている)
→オーバーライドという続きはJavaScript復習④へ
- 投稿日:2021-01-27T14:28:23+09:00
JavaScript復習②
JavaScript復習①からの続きです。
配列とfor文、length
JavaScriptファイルconst fruits = ["apple", "banana", "orange"]; for (let i = 0; i < 3 ; i ++) { console.log(fruits[i]); }コンソールapple banana orangeJavaScriptファイルconst fruits = ["apple", "banana", "orange"]; console.log(fruits.length); for (let i = 0; i < fruits.length ; i ++) { console.log(fruits[i]); }コンソール3 apple banana orange // 一つ上のファイルの条件式の箇所を i < 3 から i < fruits.length に変更してもコンソールの出力は同じである。オブジェクト
JavaScriptファイル// オブジェクト {プロパティ1: 値1, プロパティ2: 値2} {name: "チョコ", price: 150} //上の例だとname がプロパティで、"チョコ"が値 const item = {name: "チョコ", price: 150}; console.log(item); console.log(item.name);コンソール{name: "チョコ", price: 150} チョコオブジェクトの値の更新
JavaScriptファイルconst item = {name: "チョコ", price: 150}; item.price = 1,000; console.log(item.price);コンソール1,000オブジェクトを要素に持つ配列
JavaScriptファイルconst items = [ {name: "チョコ", price: 150}, {name: "ビスケット", price: 300} ]; console.log(items[1]); console.log(items[1].price); // 配列の中のオブジェクトのインデックス番号はそれぞれ、 // {name: "チョコ", price: 150}が0、{name: "ビスケット", price: 300}が1である。コンソール{name: "ビスケット", price: 300} 300undefined
配列の存在しないインデックス番号の要素やオブジェクトの存在しないプロパティの要素を取得しようとすると、
undefinedと出力される複雑なオブジェクトを扱う
JavaScriptファイルconst character = { name: "たろう", age: 20, favorite: { food: "すし", sports: "野球", color: "赤色" } }; console.log(character.favorite); console.log(character.favorite.food);コンソール{food: "すし", sports: "野球", color: "赤色"} すし関数の定義
JavaScriptファイルconst 定義名 = function() { // まとめたい処理 };JavaScriptファイルconst introduce = function() { console.log("こんにちは"); console.log("私はたろうです"); }; introduce(); //関数の呼び出しコンソールこんにちは 私はたろうですアロー関数
JavaScriptファイルconst introduce = ()=> { console.log("こんにちは"); console.log("私はたろうです"); }; introduce(); //関数の呼び出しコンソールこんにちは 私はたろうです関数内で引数を使用する
JavaScriptファイルconst introduce = (name)=> { console.log("こんにちは"); console.log(`私は${name}です`); }; introduce("たろう"); //関数の呼び出し introduce("はなこ"); //関数の呼び出しコンソールこんにちは 私はたろうです こんにちは 私ははなこです関数 引数のデフォルト値を設定する
JavaScriptファイル// 引数のデフォルト値を設定することができる function showAd(message = 'Ad'){ console.log('----------'); console.log(`---${message}---`); console.log('----------'); } . . .複数の引数を受け取る関数の呼び出し
JavaScriptファイルconst introduce = (name, age)=> { console.log(`私は${name}です`); console.log(`私は${age}歳です`); }; introduce("たろう", 20);コンソール私はたろうです 私は20歳です戻り値
JavaScriptファイルconst add = (a,b)=> { return a + b; }; const sum = add(1,3); //関数呼び出し部分 console.log(sum);コンソール4続きはJavaScript復習③へ
- 投稿日:2021-01-27T14:26:54+09:00
JavaScript復習①
ポートフォリオ作成に向けて、1月中に基礎学習を終わらせます。
HTML/CSSの復習を終わらせたので、次にJavaScriptの復習をProgate、ドットインストールを用いて行っていきます。
なお、記述する内容は自分が忘れがちな所、苦手な所です。
HTML/CSS編同様、自分用の備忘録的に投稿していくので(箇条書きで)、
読みづらいor間違えていることを書いている可能性もあるので、悪しからず。
(できるだけ他の方が見てもためになれば良いなとは思って投稿しますが・・・)
箇条書きで書いたことに関して、新たな発見、学び、気づき等あれば、
それぞれ個々に詳細を記述していこうと思います。プログラムの実行
JavaScriptファイルconsole.log('出力したい文字列'); //出力したい文字列はダブルクォーテーションorシングルクォーテーションで囲む変数の定義、命名ルール
JavaScriptファイル// 変数の定義 let name = 'Taro'; // let:変数の宣言 name:変数名 ’Taro':代入する値変数の命名ルール
○良い例・・・ 英単語を用いる、2語以上の場合は大文字で区切る
× 悪い例 ・・・ 数字で始まる、ローマ字、日本語定数の定義
JavaScriptファイル// 定数の定義 const name = 'Taro'; // const:定数の宣言 name:定数名 'Taro':代入する値テンプレートリテラルを用いた連結
JavaScriptファイルconst name = 'たろう'; console.log(`こんにちは、${name}さん`); // 出力したい内容をバッククォーテーションで囲む(シングルクォーテーションやダブルクォーテーションではなく)コンソールこんにちは、たろうさんif文のコード
JavaScriptファイルconst number = 12; if(number > 10) { console.log('numberは10より大きい'); }コンソールnumberは10より大きい比較演算子
JavaScriptファイルa === b // aとbが等しい a !== b // aとbが異なるelseのコード
JavaScriptファイルconst number = 7; if(number > 10) { console.log('numberは10より大きい'); } else { console.log('numberは10以下'); }コンソールnumberは10以下else if のコード
JavaScriptファイルconst number = 7; if(number > 10) { console.log('numberは10より大きい'); } else if (number > 5) { console.log('numberは5より大きい'); } else { console.log('numberは5以下'); }コンソールnumberは5より大きいなおかつ、または
JavaScriptファイル// x = 20 の時 console.log(x > 10 && x < 30); // true console.log(x < 10 || x > 30); // false // x = 5 の時 console.log(x > 10 && x < 30); // false console.log(x < 10 || x > 30); // trueswitch文
JavaScriptファイルconst color = "赤" switch (color){ case "red"; console.log("Stop!") break; case "yellow"; console.log("Caution"); break; case "green"; console.log("Go!"); break; default; //if文のelseに似たようなもの console.log("Wrong color") break; }switch文で条件を複数指定するときは、縦に続けて記述する。
JavaScriptファイルconst color = "赤" switch (color){ case "red"; console.log("Stop!") break; case "yellow"; console.log("Caution"); break; case "green"; case "blue"; //縦に続けて記述 console.log("Go!"); break; default; //if文のelseに似たようなもの console.log("Wrong color") break; }while文
JavaScriptファイルlet number = 1; while (number <= 100) { console.log(number); number += 1; }コンソール1 2 3 . . 99 100条件を満たせずに、処理が実行されないものを、実行するためには以下のように記述する。
JavaScriptファイルlet hp = -50 do { console.log(`${hp} HP left!); hp -= 15; } while (hp > 0);for文
JavaScriptファイルfor (let number = 1; number <= 100; number += 1) { console.log(number); } // let number = 1 ・・・ 変数の定義 // number <= 100 ・・・ 条件式 // number += 1 ・・・ 変数の更新コンソール1 2 3 . . 99 100for文でスキップさせる
JavaScriptファイルfor (let i = 1; i <= 10; i++) { if(i === 4){ continue; } console.log(i); }コンソール//4がスキップされる 1 2 3 5 6 7 8 9 10for文でストップさせる
JavaScriptファイルfor (let i = 1; i <= 10; i++) { if(i === 4) { break; } console.log(i); }コンソール1 2 3配列を定数に代入する、インデックス番号、配列の要素更新
JavaScriptファイルconst fruits = ["apple", "banana", "orange"]; console.log(fruits); console.log(fruits[0]); console.log(fruits[2]); fruits[0] = "grape"; console.log(fruits[0]); // 上記のfruitsの部分は定数名と言う // インデックス番号はそれぞれ、"apple"が0、"banana"が1、"orange"が2コンソール["apple", "banana", "orange"] apple orange grape続きはJavaScript復習②へ
- 投稿日:2021-01-27T14:10:22+09:00
bulletml.jsの研究 その4
概要
bulletml.jsの研究です。
技を調査。自機狙い
<bulletml> <action label="top"> <repeat> <times>222</times> <action> <fire> <direction type="sequence">23</direction> <bullet> <action> <wait>20 + $rand * 50</wait> <changeDirection> <direction type="aim">0</direction> <term>10</term> </changeDirection> </action> </bullet> </fire> <wait>1</wait> </action> </repeat> </action> </bulletml>説明
自機の位置を狙ってくる弾です。
弾幕パターンの基本中の基本と言えるでしょう。大量に出現するザコ敵は、この攻撃を行うのが一般的です。
発射方向を微妙にずらして撃つ場合もあります。
特に、プレイヤーが回避する移動先に撃つなどすると面白いでしょう。成果物
https://embed.plnkr.co/plunk/9P8WLf4RAfR2J3bY
以上。
- 投稿日:2021-01-27T13:56:09+09:00
Rails 非同期通信 メッセージ機能の実装
メッセージの非同期通信の実装
メッセージの非同期にあたり大きく分けて二つの機能を実装しました、
一つは非同期通信のメッセージ送信です。
二つ目はメッセージの受信(自動更新機能)です。
今回はJavaScriptのみのコードを公開しております。途中に参考にした記事などを掲載しております。そちらを参照していただければと思います。
その前に非同期通信とは?
コンピュータ間でデータ送信と受信のタイミングを合わせずに行う通信手段である。片方がオンライン状態であれば、データの送受信を行うことができる。
反対に同期通信というものがある。
同期通信とは、送信側も受信側もオンラインである必要があり、片方が接続してれば通信を行える非同期通信とは大きく違う点である。それを踏まえて一つ目のメッセージの送信について、
$(document).on('turbolinks:load', function(){ function buildHTML(message) { var content = message.content ? `${ message.content }` : ""; var img = message.image ? `<img src= ${ message.image }>` : ""; var html = `<div class= "message" data-message-id=${message.id}> <div class="upper-message"> <p class="message-user"> ${message.user_name} </p> <p class="message-date"> ${message.date} </p> </div> <p class="lower-message"> <div class="message-content"> ${content} </div> </p> </div>` return html; } $('#new_message').on('submit', function(e){ e.preventDefault(); var message = new FormData(this); var url = (window.location.href); $.ajax({ url: url, type: 'POST', data: message, dataType: 'json', processData: false, contentType: false }) .done(function(data){ var html = buildHTML(data); $('.messages').append(html); $('#message_content').val(''); scrollBottom(); }) .fail(function(data){ alert('エラーが発生したためメッセージは送信できませんでした。'); }) .always(function(data){ $('.form-submit').prop('disabled', false); }) })こちらに関するコードは下記のURLを参考にして実装いたしました、この方の記事を読んだ方が効率がいいので参考にしていただければと思います。
(引用https://qiita.com/mmmasuke/items/36365bcdf30eaea65250)二つ目のメッセージの受信(自動更新機能)について
var reloadMessages = function(){ var href = 'api/messages#index {:format=>"json"}' var last_message_id = $('.message:last').data('message-id'); $.ajax({ url: href, type: 'GET', data: {id: last_message_id}, dataType: 'json', }) .done(function(messages) { if (messages.length !== 0) { var insertHTML = ''; $.each(messages, function(i, message) { insertHTML += buildHTML(message) }); $('.messages').append(insertHTML); $('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight}); } }) .fail(function(){ alert("自動更新に失敗しました") }); }; if (document.location.href.match(/\/rooms\/\d+\/messages/)){ setInterval(reloadMessages, 7000)}; }); function scrollBottom(){ var target = $('.message').last(); var position = target.offset().top + $('.messages').scrollTop(); $('.messages').animate({ scrollTop: position }, 300, 'swing'); }こちらのコードは
(引用https://qiita.com/AK4747471/items/cc0ba52b6ed34f0b4b8c)
こちらの記事を参考に実装いたしました。ただの感想
実装にあたり、自身が送信のみで非同期通信を実装できたと勘違いしておりました。メッセージの非同期通信には自動更新は必須です。





























