20210610のJavaScriptに関する記事は16件です。

【three.js】Meshに枠線を追加しアニメーションする

作るもの⤵︎ 先に完成物 僕みたいにせっかちな方はこちらからどうぞ! 省略しているので、実際に使うときは関数にまとめるなりしてくださいまし。 js // 二十面体のgeometryとmaterialを定義 const geometry = new THREE.IcosahedronGeometry(300, 3); // 半径, 面の細かさ const material = new THREE.MeshBasicMaterial({ color: 0x49ef4 }); // 二十面体の色 // 二十面体を作成 const icosahedron = new THREE.Mesh(geometry, material); // 枠線を作成 const icosahedronLine = new THREE.LineSegments( new THREE.EdgesGeometry(geometry), // 線を生成する元になるgeometry new THREE.LineBasicMaterial({ color: 0xffffff }) // 線のmaterial ); // 二十面体に枠線を追加 icosahedron.add(icosahedronLine); // sceneに追加 scene.add(icosahedron); function animate() { // 再帰 requestAnimationFrame(animate); // レンダリング renderer.render(scene, camera); // 二十面体を回転させる icosahedron.rotation.y += 0.01; } // 関数呼び出し animation(); 元となるコード シーンやカメラ、レンダラーは作成済みとする。 js // 二十面体のgeometryとmaterialを定義 const geometry = new THREE.IcosahedronGeometry(300, 3); // 半径, 面の細かさ const material = new THREE.MeshBasicMaterial({ color: 0x49ef4 }); // 二十面体の色 // 二十面体を作成 const icosahedron = new THREE.Mesh(geometry, material); // sceneに追加 scene.add(icosahedron) 枠線を追加する LineSegments、EdgesGeometryを用いて作成する。 js // 二十面体のgeometryとmaterialを定義 const geometry = new THREE.IcosahedronGeometry(300, 3); // 半径, 面の細かさ const material = new THREE.MeshBasicMaterial({ color: 0x49ef4 }); // 二十面体の色 // 二十面体を作成 const icosahedron = new THREE.Mesh(geometry, material); + // 枠線を作成 + const icosahedronLine = new THREE.LineSegments( + new THREE.EdgesGeometry(geometry), // 線を生成する元になるgeometry + new THREE.LineBasicMaterial({ color: 0xffffff }) // 線のmaterial + ); // sceneに追加 scene.add(icosahedron); + scene.add(icosahedronLine); アニメーション 円が回転するアニメーションを追加してみる。 js + function animate() { + // 再帰 + requestAnimationFrame(animate); + // レンダリング + renderer.render(scene, camera); + // 二十面体を回転させる + icosahedron.rotation.y += 0.01; + icosahedronLine.rotation.y += 0.01; + } + // 関数呼び出し + animation(); 回った! 枠線を立体に結合する これで完成でも良いが、この十二面体をアニメーションするたびに毎回icosahedronとicosahedronLineを指定するのは面倒くさい。 ので、シーンではなく十二面体に枠線を追加する。(これが出来るのに気づかず一晩潰した) アニメーションのターゲットから外すのを忘れずに。 js // 二十面体のgeometryとmaterialを定義 const geometry = new THREE.IcosahedronGeometry(300, 3); // 半径, 面の細かさ const material = new THREE.MeshBasicMaterial({ color: 0x49ef4 }); // 二十面体の色 // 二十面体を作成 const icosahedron = new THREE.Mesh(geometry, material); // 枠線を作成 const icosahedronLine = new THREE.LineSegments( new THREE.EdgesGeometry(geometry), // 線を生成する元になるgeometry new THREE.LineBasicMaterial({ color: 0xffffff }) // 線のmaterial ); // sceneに十二面体を追加 scene.add(icosahedron); - // scene.add(icosahedronLine); // 十二面体に枠線を追加 + icosahedron.add(icosahedronLine); function animate() { // 再帰 requestAnimationFrame(animate); // レンダリング renderer.render(scene, camera); // 二十面体を回転させる icosahedron.rotation.y += 0.01; - // icosahedronLine.rotation.y += 0.01; } // 関数呼び出し animation(); これで、icosahedronをanimate()やらAnimationMixerやらでアニメーションさせれば枠線も一緒にアニメーションするようになった。 おしまい 意外と検索に引っ掛からなかったので、メモがてら掲載しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

InDesign スクリプト 要素の内容を配置(ページにあるマスターページのページアイテムに)

ページにあるマスターページのページアイテムに要素の内容を配置するスクリプトは、これで良いのかな・・・? /* ページにあるマスターページのページアイテムに要素の内容を配置 更新 2021/06/10 配置に使うXMLの例 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Root> <!--順番を調べる為のXML--> <ページ placePageNumber="1"> <順番 masterPageItemIndex="1">1</順番> <順番 masterPageItemIndex="2">2</順番> <順番 masterPageItemIndex="3">3</順番> <順番 masterPageItemIndex="4">4</順番> <順番 masterPageItemIndex="5">5</順番> <順番 masterPageItemIndex="6">6</順番> <順番 masterPageItemIndex="7">7</順番> <順番 masterPageItemIndex="8">8</順番> <順番 masterPageItemIndex="9">9</順番> <順番 masterPageItemIndex="10">10</順番> </ページ> </Root> */ // アプリ指定 #target "indesign"; // スクリプト名 var scriptName = "要素の内容を配置(ページにあるマスターページのページアイテムに)"; //スクリプトの動作指定(一つのアンドゥ履歴にする、及び、アンドゥ名) app.doScript(function () { // 配置ページ番号を指定する属性の属性名 var placePageNumberAssignAttributeName ="placePageNumber"; // マスターページのページアイテムを指定する属性の属性名 var masterPageItemAssignAttributeName = "masterPageItemIndex"; // 選択されているオブジェクト var selectObjects = []; // 子供の要素 var childElements = []; // 配置ページ var placePage; // 配置ページ番号 var placePageNumber; // マスターページのページのページアイテムの順番 var masterPagePagePageItemAssignNumber // 配置予定数 var expectationPlaceNumber = 0; // 配置数 var placeNumber = 0; // ダイアログ var dialogueFlg = confirm("ページにあるオーバーライドされていないマスターページのページアイテムに要素の内容を配置します。" + "\r\r" + "ページを指定するのに" + placePageNumberAssignAttributeName + "名の属性とその値(ページ番号)を使用します。" + "\r\r" + "ページにあるオーバーライドされていないマスターページのページアイテムを指定するのに" + masterPageItemAssignAttributeName + "名の属性とその値(ページアイテムのページでの順番)を使用します。" + "\r\r" + "マスターページのページアイテムがロックされている場合はそのページアイテムには配置されません。", "", scriptName); // Noの場合 if (dialogueFlg == false) { // 終了 exit(); } // すべての選択を入れる selectObjects = app.activeDocument.selection; // すべての選択を解除 app.activeDocument.selection = null; // 選択の数だけ繰り返す for(var i = 0; i < selectObjects.length; i++){ // 選択が要素の場合 if (selectObjects[i].constructor.name == "XMLElement"){ // placePageNumberAssignAttributeName名の属性がある場合 if(selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).isValid == true){ // 属性の値が数字の場合 if(selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).value.match(/^[1-9][0-9]*$/) != null){ // 属性の値を入れる placePageNumber = selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).value; // ページの数だけ繰り返す for(var ii = 0; ii < app.activeDocument.pages.length; ii++){ // ページが存在する場合 if(app.activeDocument.pages[ii].name == placePageNumber){ // ページを入れる placePage = app.activeDocument.pages[ii]; // 子供の要素を入れる childElements = selectObjects[i].evaluateXPathExpression("//*/*"); // 子供の要素の数だけ繰り返す for(var iii = 0; iii < childElements.length; iii++){ // XmlStoryの場合(未配置) if(getStoryConstructorName(childElements[iii]) == "XmlStory"){ // masterPageItemAssignAttributeName名の属性がある場合 if(childElements[iii].xmlAttributes.itemByName(masterPageItemAssignAttributeName).isValid == true){ // 属性の値を入れる masterPagePagePageItemAssignNumber = childElements[iii].xmlAttributes.itemByName(masterPageItemAssignAttributeName).value; // 数を追加 expectationPlaceNumber++; // 属性の値が数字の場合 if(masterPagePagePageItemAssignNumber.match(/^[1-9][0-9]*$/) != null){ // ページにオーバーライドされていないマスターページのページアイテムが存在する場合 if(placePage.masterPageItems.length > 0){ // ページアイテムの順番の数よりページのオーバーライドされていないマスターページのページアイテムの一つ目のマスターページのページのページアイテムの数が多いか同じ場合 if(masterPagePagePageItemAssignNumber <= placePage.masterPageItems[0].parentPage.allPageItems.length){ // ページにあるオーバーライドされていないマスターページのページアイテムの数だけ繰り返す for(var iiii = 0; iiii < placePage.masterPageItems.length; iiii++){ // ページのオーバーライドされていないマスターページのページアイテムのIdとページのオーバーライドされていないマスターページのページアイテムの一つ目のマスターページのページの順番で指定したページアイテムのIdが一致する場合 if(placePage.masterPageItems[iiii].id == placePage.masterPageItems[0].parentPage.allPageItems[masterPagePagePageItemAssignNumber - 1].id){ // ロックされていない場合 if(placePage.masterPageItems[iiii].locked == false){ // geometricBoundsプロパティを持っている場合 if(placePage.masterPageItems[iiii].hasOwnProperty("geometricBounds") == true){ // オーバーライドして配置 childElements[iii].placeXML(placePage.masterPageItems[iiii].override(placePage)); // 数を追加 placeNumber++; // 繰り返しを抜ける break; } } } } } } } } } } // 繰り返しを抜ける break; } } } } } } // 結果を表示 alert("指定数(選択された要素の子供で" + masterPageItemAssignAttributeName+ "名の属性を持つ要素の数 ) " + expectationPlaceNumber + "\r\r" + "配置数 " + placeNumber, scriptName); //スクリプトの動作指定の続き }, ScriptLanguage.JAVASCRIPT, [scriptName], UndoModes.ENTIRE_SCRIPT, scriptName); /* ストーリーのコンストラクタ名を取得する関数、引数(オブジェクト)の宣言 */ function getStoryConstructorName(anyObject) { // parentStoryプロパティが存在する場合 if (anyObject.hasOwnProperty("parentStory") == true) { // parentStoryに値がある場合 if (anyObject.parentStory) { // ストーリーのコンストラクタ名を戻す return anyObject.parentStory.constructor.name; } // スプレッドの場合 } else if (anyObject.constructor.name == "Spread") { // 抜ける return; } // 階層を一つ上げて再帰関数 return getStoryConstructorName(anyObject.parent); } /* ストーリーのコンストラクタ名を取得する関数の宣言終了 */ たとえば 以下の様なXML(文字コードはUTF-8)をInDesignの構造に読み込み スクリプトを実行して下さい。 要素の選択を補助するスクリプトあります。 1つの要素を複数配置する事は出来ません。 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Root> <!--順番を調べる為のXML--> <ページ placePageNumber="1"> <順番 masterPageItemIndex="1">1</順番> <順番 masterPageItemIndex="2">2</順番> <順番 masterPageItemIndex="3">3</順番> <順番 masterPageItemIndex="4">4</順番> <順番 masterPageItemIndex="5">5</順番> <順番 masterPageItemIndex="6">6</順番> <順番 masterPageItemIndex="7">7</順番> <順番 masterPageItemIndex="8">8</順番> <順番 masterPageItemIndex="9">9</順番> <順番 masterPageItemIndex="10">10</順番> </ページ> </Root>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

InDesign スクリプト 要素を配置(マスターページをオーバーライドして)

マスターページをオーバーライドして要素を配置するスクリプトは、これで良いのかな・・・? /* マスターページをオーバーライドして要素を配置 更新 2021/06/12 配置に使うXMLの例 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Root> <!--文字コードに注意--> <!--順番を調べる為のXML--> <ページ placePageNumber="1"> <順番 masterPageItemNumber="1">1</順番> <順番 masterPageItemNumber="2">2</順番> <順番 masterPageItemNumber="3">3</順番> <順番 masterPageItemNumber="4">4</順番> <順番 masterPageItemNumber="5">5</順番> <順番 masterPageItemNumber="6">6</順番> <順番 masterPageItemNumber="7">7</順番> <順番 masterPageItemNumber="8">8</順番> <順番 masterPageItemNumber="9">9</順番> <順番 masterPageItemNumber="10">10</順番> </ページ> </Root> */ // アプリ指定 #target "indesign"; // スクリプト名 var scriptName = "要素を配置(マスターページをオーバーライドして)"; //スクリプトの動作指定(一つのアンドゥ履歴にする、及び、アンドゥ名) app.doScript(function () { // 配置ページ番号を指定する属性の属性名 var placePageNumberAssignAttributeName ="placePageNumber"; // マスターページのページアイテムを指定する属性の属性名 var masterPageItemAssignAttributeName = "masterPageItemNumber"; // 選択されているオブジェクト var selectObjects = []; // 子供の要素 var childElements = []; // 配置ページ var placePage; // 配置ページ番号 var placePageNumber; // マスターページのページのページアイテムの順番 var masterPagePagePageItemAssignNumber // 配置予定数 var expectationPlaceNumber = 0; // 配置数 var placeNumber = 0; // ダイアログ var dialogueFlg = confirm("ページにあるオーバーライドされていないマスターページのページアイテムに要素を配置します。" + "\r\r" + "ページを指定するのに" + placePageNumberAssignAttributeName + "名の属性とその値(ページ番号)を使用します。" + "\r\r" + "ページにあるオーバーライドされていないマスターページのページアイテムを指定するのに" + masterPageItemAssignAttributeName + "名の属性とその値(ページアイテムのページでの順番)を使用します。" + "\r\r" + "マスターページのページアイテムがロックされている場合はそのページアイテムには配置されません。", "", scriptName); // Noの場合 if (dialogueFlg == false) { // 終了 exit(); } // すべての選択を入れる selectObjects = app.activeDocument.selection; // すべての選択を解除 app.activeDocument.selection = null; // 選択の数だけ繰り返す for(var i = 0; i < selectObjects.length; i++){ // 選択が要素の場合 if (selectObjects[i].constructor.name == "XMLElement"){ // placePageNumberAssignAttributeName名の属性がある場合 if(selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).isValid == true){ // 属性の値が数字の場合 if(selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).value.match(/^[1-9][0-9]*$/) != null){ // 属性の値を入れる placePageNumber = selectObjects[i].xmlAttributes.itemByName(placePageNumberAssignAttributeName).value; // ページの数だけ繰り返す for(var ii = 0; ii < app.activeDocument.pages.length; ii++){ // ページが存在する場合 if(app.activeDocument.pages[ii].name == placePageNumber){ // ページを入れる placePage = app.activeDocument.pages[ii]; // 子供の要素を入れる childElements = selectObjects[i].evaluateXPathExpression("//*/*"); // 子供の要素の数だけ繰り返す for(var iii = 0; iii < childElements.length; iii++){ // XmlStoryの場合(未配置) if(getStoryConstructorName(childElements[iii]) == "XmlStory"){ // masterPageItemAssignAttributeName名の属性がある場合 if(childElements[iii].xmlAttributes.itemByName(masterPageItemAssignAttributeName).isValid == true){ // 属性の値を入れる masterPagePagePageItemAssignNumber = childElements[iii].xmlAttributes.itemByName(masterPageItemAssignAttributeName).value; // 数を追加 expectationPlaceNumber++; // 属性の値が数字の場合 if(masterPagePagePageItemAssignNumber.match(/^[1-9][0-9]*$/) != null){ // ページにオーバーライドされていないマスターページのページアイテムが存在する場合 if(placePage.masterPageItems.length > 0){ // ページアイテムの順番がマスターページのページアイテムの順番の範囲内の場合 if(masterPagePagePageItemAssignNumber <= placePage.masterPageItems[0].parentPage.allPageItems.length){ // ページにあるオーバーライドされていないマスターページのページアイテムの数だけ繰り返す for(var iiii = 0; iiii < placePage.masterPageItems.length; iiii++){ // ページのオーバーライドされていないマスターページのページアイテムのIdとページのオーバーライドされていないマスターページのページアイテムの一つ目のマスターページのページの順番で指定したページアイテムのIdが一致する場合 if(placePage.masterPageItems[iiii].id == placePage.masterPageItems[0].parentPage.allPageItems[masterPagePagePageItemAssignNumber - 1].id){ // ロックされていない場合 if(placePage.masterPageItems[iiii].locked == false){ // geometricBoundsプロパティを持っている場合 if(placePage.masterPageItems[iiii].hasOwnProperty("geometricBounds") == true){ // オーバーライドして配置 childElements[iii].placeXML(placePage.masterPageItems[iiii].override(placePage)); // 数を追加 placeNumber++; // 繰り返しを抜ける break; } } } } } } } } } } // 繰り返しを抜ける break; } } } } } } // 結果を表示 alert("指定数(選択された要素の子供で" + masterPageItemAssignAttributeName+ "名の属性を持つ要素の数 ) " + expectationPlaceNumber + "\r\r" + "配置数 " + placeNumber, scriptName); //スクリプトの動作指定の続き }, ScriptLanguage.JAVASCRIPT, [scriptName], UndoModes.ENTIRE_SCRIPT, scriptName); /* ストーリーのコンストラクタ名を取得する関数、引数(オブジェクト)の宣言 */ function getStoryConstructorName(anyObject) { // parentStoryプロパティが存在する場合 if (anyObject.hasOwnProperty("parentStory") == true) { // エラー処理 try{ // parentStoryの値がある場合 if (anyObject.parentStory) { // コンストラクタ名を戻す return anyObject.parentStory.constructor.name; } // エラーの場合 }catch(e){ // 抜ける return; } // Applicationの場合 } else if (anyObject.constructor.name == "Application") { // 抜ける return; } // オブジェクトの階層を一つ上げて再帰関数 return getStoryConstructorName(anyObject.parent); } /* ストーリーのコンストラクタ名を取得する関数の宣言終了 */
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでMap -> Object

Mapって便利ですが、JSONにするとき困りますよね? const m = new Map(); m.set("a","1"); m.set("b","2"); console.log(JSON.stringify(m)); // {} なんか無理やり? const m = new Map(); m.set("a","1"); m.set("b","2"); const o = Object.assign({},...[...m.entries()].map(m=>({[m[0]]:m[1]}))); console.log(JSON.stringify(o)); // {"0":"b","1":"2"} もっといい方法無いのでしょうか?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Blenderで出力した3DモデルをAR.jsで使う

AR.jsで表示する3Dモデルを無料サイトで探していたのですが、Blenderのプロジェクト形式でしか配布していないモデルがあり、じゃあBlenderでglbファイルにしてやれば良いじゃんとなった際のやり方。 環境はBlender2.93.0です。 Blenderのインストール ここからできます。 基本的に画面上部の青いボタンを押せば環境に合ったものがダウンロードできると思いますが、 もし違うものになっていたら少し下にあるドロップダウンリストから選ぶとダウンロードできます。 ダウンロードしたらインストーラーの指示に従いながらインストール。 何も考えずにNextを選んでいけば大丈夫。 対象のプロジェクトを開く Blenderを立ち上げて、言語の設定をすると以下の様な画面が出てくるので左下の「開く」を選択して、 対象のプロジェクトを開きます。 glbファイルとしてエクスポート プロジェクトを開いたら早速エクスポートします。 画面左上のツールバーから「ファイル」⇒「エクスポート」⇒「glTF2.0(.glb/.gltf)」を選択 出力先の選択ダイアログが出てくるので右上のフォーマットから「glTFバイナリ(.glb)」を選択 最後に右下の「glTF2.0をエクスポート」を選択すればglbファイルがエクスポートされます。 AR.jsでの使用 後はglbファイルを適当なアップローダーでWeb上に置いて、AR.jsから参照できるようにすればOK <a-entity position="0 0 0" rotation="0 0 0" scale="0.05 0.05 0.05" gltf-model="https://arjs-cors-proxy.herokuapp.com/アップロードファイルのURL" ></a-entity>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Object.values() が便利だから(?) Javascript では配列よりハッシュを積極的に使おう

まぁ表題のままなので、あまり書くような事もないんですが。 つまり const object1 = { a: 'somestring', b: 42, c: false }; console.log(Object.values(object1)); // expected output: Array ["somestring", 42, false] こういう事なんですが、具体的にどういう場面で使えるのか、というところについて書きたいと思います。 配列管理 const user = { id: 123456, name: 'Alice', mail: 'alice@example.com' } こういうデータがあったとして id はいわゆる主キーとして機能する id は規則的ではない id 以外の情報は書き換えが存在する このデータを沢山管理する必要があった時に素朴に思いつくのは配列だと思います。 const users = [ { id: 123456, name: 'Alice', mail: 'alice@example.com' }, { id: 573940, name: 'Bob', mail: 'bobie@example.com' }, .... ] こうすると「 id: 999 のデータを探したい」ってなった時にこうなると思います const userThreeNine = users.find(u => u.id === 999) 情報を更新したいってなったらこうなりますね。実際はもっと多くのプロパティ持ってるでしょうし、ロジック分けるのもめんどうなので「情報を全部貰ってリプレイスする」方がいいと思うので、こうなる事の方が多いと思います。 Object.assign(users.find(u => u.id === 999), newData) 一番面倒なのはこの配列からデータを削除したい場合です。多分こうなると思います。 users.splice(users.findIndex(u => u.id === 999), 1) 配列使ってるんだからこうだよね、という感じのごくごくあたりまえのコードに見えますが、パッと見でこのコードを理解できますか? あとは、たとえば大量のデータを処理しようとした時にかかるオーダーは全体数を $n$、更新数を $m$ とした場合に $ O(n,m) = log(n)*m $ です。 別に目を顰めるオーダーではないですが、減らせるんなら減らしたいですよね。 ハッシュ管理 なので、こうしてしまいましょう。 const userThreeNine = { id: 999, name: 'Three Nine', mail: 'three.nine@example.com' } users[hogeUser.id] = hogeUser 検索も存在確認も削除も以下の通りです。 const id = 999 const userThreeNine = users[id] // 検索 const hogeUserNewData = {...} users[hogeUserNewData.id] = hogeUserNewData // 更新 const deleteUserId = 666 delete users[deleteUserId] // 削除 コードも直感的になったし、勿論検索コストは $ O(n, m) = m $ です。 これで万事解決!といいたいところですが…… 配列だからこそできたこと 各要素でのソート 主キー以外での検索/フィルタリング とかとか、「配列でできた事ができなくなったじゃないか!」と思っているでしょう。 素朴に書くなら、例えば検索なら for...in を使えばできそうです。 const hasHogeIsHuga (user) { return user.hoge === 'huga' } const findSomtehing (users, hasHogeIsHuga) { const result = [] for(const p in users){ if( hasHogeIsHuga(users[p]) ){ result.push(users[p]) } } return result } なんじゃこれ。ってなりますね。 そこで Object.values() 一番最初に書いたように、この関数はオブジェクトを配列の形に開いてくれます。 なので例えば // フィルタリング const hasHogeHugaUsers = Object.values(users).filter(hasHogeIsHuga) // ソート const usersSortedByPoint = Object.values(users).sort((a,b) => a.point - b.point) のように書けるわけです。便利! という訳で ハッシュ管理は見やすいよ Object.values() は便利だよ という話でした。 見やすいコードに貢献してくれると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

第 9 章 Hooks 、関数コンポーネントの合体強化 パーツ メモ

コミュニティによって普及した HOC HOC とはコンポーネント を引数に取り、戻り値としてコンポーネントを返す関数のこと。 render props render props は必 ずしも render という名前の props を使う必要はなくてね。そのコンポーネントが自身のレンダリン グのために使うコンポーネントの props は、何だろうと技術的には render props と呼ぶの HOC より render props のほうが優れていると主張する理由は次のようなもの ・HOC のように props の名前の衝突が起こりづらく、起こったとしてもコードから一目瞭然 ・TypeScript 使用時、props の型合成が必要ない ・どの変数が機能を注入するための props として親コンポーネントに託されたのかがコードから 判別しやすい ・コンポーネントの外で結合させる必要がなく、JSX の中で動的に扱うことができる ついに Hooks が登場する Hooks は公式が新たに React の機能として提供したもの Hooks はコンポーネントにロジックを抱えた別のコンポーネントをかぶせるのではなく、コンポーネント システムの外に状態やロジックを持つ手段を提供した Hooks を使えば、状態を持ったロジックを完全に任意の コンポーネントから切り離し、それ単独でテストしたり、別のコンポーネントで再利用することが 簡単にできるようになる。コンポーネントの階層構造を変えることなしに、状態を伴った再利用可 能なロジックを追加できるというのが画期的だった Hooks がコンポーネントシステムの外に状態やロジックを 持つしくみを提供したことによって、ほぼ関数コンポーネントだけでアプリケーションが作れるよ うになったの。というか Hooks は関数コンポーネント内でしか使えない 2021 年 3 月現在 getSnapshotBeforeUpdate、getDerivedStateFromError、componentDidCatch の 3 つのライフサイクルメソッドに相当する機能は Hooks では提供されてない ただ将来的には 追加される予定 新しく作るコンポーネン トは Hooks と関数コンポーネントで作ることが推奨されている Hooks で state を扱う State Hook といってクラスコンポーネントの state に相当するものを関数コンポーネントでも使えるようにする機能 useState という関数を 使う const [count, setCount] = useState(0); setCount(100); setCount(prevCount => prevCount + 1); useState は戻り値として state 変数とその state 更新関数をタプルとして返す だから上の ように分割代入で受け取る 配列の分割代入と同様なのでもちろん、state 変数とその更新関数 の名前は好きなものに設定できる useState(INITIAL_VALUE) のように引数を渡すと、その値が state 変数の初期値として設定される import { VFC, useState } from 'react'; import { Button, Card, Statistic } from 'semantic-ui-react'; import './Counter.css'; const Counter: VFC = () => { const [count, setCount] = useState(0); const increment = () => setCount((c) => c + 1); const reset = () => setCount(0); return ( <Card> <Statistic className="number-board"> <Statistic.Label>count</Statistic.Label> <Statistic.Value>{count}</Statistic.Value> </Statistic> <Card.Content> <div className="ui two buttons"> <Button color="red" onClick={reset}> Reset </Button> <Button color="green" onClick={increment}> +1 </Button> </div> </Card.Content> </Card> ); }; export default Counter; const plusThreeDirectly = () => [0, 1, 2].forEach((_) => setCount(count + 1)); const plusThreeWithFunction = () => [0, 1, 2].forEach((_) => setCount((c) => c + 1)); state 変数はそのコンポーネントのレンダリングごとで一定 よって plusThreeDirectly() はそ のレンダリング時点での count が 0 だったとしたら、それを 1 に上書きする処理を 3 回繰り返すこ とになる だから state 変数を相対的に変更する処理を行うときは、前の値を直接参照・変更 するのは避けて必ず setCount((c) => c + 1) のように関数で書くべき Hooks の呼び出しはその関数コンポーネントの論理階層の トップレベルでないといけない Hooks で副作用を扱う Effect Hook の使い方 副作用を扱う Hooks API を Effect Hook という コンポーネントの『副作用』とは ネットワークを介したデータの取 得やそのリアクティブな購読、ログの記録、リアル DOM の手動での書き換えといったもの Effect Hook とは、props が同一であってもその関数コンポーネントの出力内容を変えてしまうような処理をレンダリングの タイミングに同期させて実行するための Hooks API のこと useEffect という関数を使う const SampleComponent: VFC = () => { const [data, setData] = useState(null); … useEffect(() => { doSomething(); return () => clearSomething(); }, [someDeps]); … }; まず useEffect は第 1 引数として、引数を持たない関数を受け取る。この関数 の中身が任意のタイミングで実行される useEffect へ第 1 引数として渡す関数がその戻り値として任意の関数を返すように しておくと、そのコンポーネントがアンマウントされるときにその戻り値の関数を実行してくれる useEffect の第 2 引数、ここには変数の配列を渡せるようになってる この配列の中 に格納された変数がひとつでも前のレンダリング時と比較して差分があったときだけ、第 1 引数の 関数が実行される この第 2 引数のことを 依存配列(dependencies array)ともいう 第 2 引数は省略可能 ただし依存配列が渡されなかった場合、レンダリングごとに毎回第 1 引数 の関数が実行されることになる 空配列 [] を渡すと、初回のレンダリング時にのみ第 1 引数の関数が実行される import { VFC, useEffect, useState } from 'react'; import { Button, Card, Icon, Statistic } from 'semantic-ui-react'; import './Timer.css'; const Timer: VFC<{ limit: number }> = ({ limit }) => { const [timeLeft, setTimeLeft] = useState(limit); const reset = (): void => setTimeLeft(limit); const tick = (): void => setTimeLeft((t) => t - 1); useEffect(() => { const timerId = setInterval(tick, 1000); return () => clearInterval(timerId); }, []); // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => { if (timeLeft === 0) setTimeLeft(limit); }); return ( <Card> <Statistic className="number-board"> <Statistic.Label>time</Statistic.Label> <Statistic.Value>{timeLeft}</Statistic.Value> </Statistic> <Card.Content> <Button color="red" fluid onClick={reset}> <Icon name="redo" /> Reset </Button> </Card.Content> </Card> ); }; export default Timer; Effect Hook とライフサイクルメソッドの相違点 実行されるタイミング props と state の値の即時性 凝集の単位 1. 実行されるタイミング useEffect が初回実行されるのは、最初のレンダリングが行われてその内容がブラウザ に反映された直後。コンポーネントはまず初期値でレンダリングされた後、あらためて副作用が反 映された内容で再レンダリングされる 2. props と state の値の即時性 クラスコンポーネントのメンバーメソッドで参照される props や state は常に最新の値だけど、そ のため負荷のかかる処理を伴う UI ではタイムラグを考慮する必要がある。処理に時間がかかって レンダリングが追いつかない状態で UI を操作をすると、新しすぎる props や state の値が想定外の 挙動を起こすことがあるの。 いっぽう関数コンポーネント内部におけるそれらはレンダリングのタイミングで固定されている ため、同様の問題は起きない。 ブログ記事『関数コンポーネントはクラスとどうちがうのか?』 3. 凝集の単位 Effect Hook はライフサイクルメソッドに比べて機能的凝集度が高い 機能的凝集度が高いということは、同じ機能が分散して記述されないためコードの可読性が高い のはもちろん、機能によってまとまったロジックをコンポーネントから切り離して再利用しやすい ということでもある Hooks におけるメモ化を理解する メモ化とはプログラム高速化の手法のこと import { VFC, useEffect, useMemo, useState } from 'react'; import { Button, Card, Icon, Statistic } from 'semantic-ui-react'; import { getPrimes } from 'utils/math-tool'; import './Timer.css'; type TimerProps = { limit: number; }; const Timer: VFC<TimerProps> = ({ limit }) => { const [timeLeft, setTimeLeft] = useState(limit); const primes = useMemo(() => getPrimes(limit), [limit]); const reset = () => setTimeLeft(limit); const tick = () => setTimeLeft((t) => t - 1); useEffect(() => { const timerId = setInterval(tick, 1000); return () => clearInterval(timerId); }, []); useEffect(() => { if (timeLeft === 0) setTimeLeft(limit); }, [timeLeft, limit]); return ( <Card> <Statistic className="number-board"> <Statistic.Label>time</Statistic.Label> <Statistic.Value className={primes.includes(timeLeft) ? 'prime-number' : undefined} > {timeLeft} </Statistic.Value> </Statistic> <Card.Content> <Button color="red" fluid onClick={reset}> <Icon name="redo" /> Reset </Button> </Card.Content> </Card> ); }; export default Timer; useMemo を使って計算結果をコンポーネン トシステムの外に保存しておく useMemo は useEffect と同じインターフェース 第 1 引数に実行したい関 数、第 2 引数にその依存配列を渡してる useMemo が関数の実行結果をメモ化する Hooks API だったのに対して、useCallback は関数定義そ のものをメモ化するためのもの メモ化はパフォーマンスの最適化以外に、依存関係を適切化して不要な再レンダリングを避けるためにも用いられることがある useRef は useState とちがって値の変更がコンポーネントの再レンダリングを発生させない Custom Hook でロジックを分離・再利用する コンポーネントから Hooks のロジックを切り出したものを『Custom Hook』って呼ぶ Custom Hook 関数の名前の頭に『use』をつける import { VFC } from 'react'; import { Button, Card, Icon, Statistic } from 'semantic-ui-react'; import useTimer from 'hooks/use-timer'; import 'components/Timer.css'; const Timer: VFC<{ limit: number }> = ({ limit }) => { const [timeLeft, isPrime, reset] = useTimer(limit); return ( <Card> <Statistic className="number-board"> <Statistic.Label>time</Statistic.Label> <Statistic.Value className={isPrime ? 'prime-number' : undefined}> {timeLeft} </Statistic.Value> </Statistic> <Card.Content> <Button color="red" fluid onClick={reset}> <Icon name="redo" /> Reset </Button> </Card.Content> </Card> ); }; export default Timer; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { getPrimes } from 'utils/math-tool'; const useTimer = (limit: number): [number, boolean, () => void] => { const [timeLeft, setTimeLeft] = useState(limit); const primes = useMemo(() => getPrimes(limit), [limit]); const timerId = useRef<NodeJS.Timeout>(); const tick = () => setTimeLeft((t) => t - 1); const clearTimer = () => { if (timerId.current) clearInterval(timerId.current); }; const reset = useCallback(() => { clearTimer(); timerId.current = setInterval(tick, 1000); setTimeLeft(limit); }, [limit]); useEffect(() => { reset(); return clearTimer; }, [reset]); useEffect(() => { if (timeLeft === 0) reset(); }, [timeLeft, reset]); return [timeLeft, primes.includes(timeLeft), reset]; }; export default useTimer;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2021】VSCode フロントエンド・コーダー必見のおすすめ設定・拡張機能

大人気のテキストエディタで既にたくさんの記事も出ておりますが、 こちらでは、コーディングに特化した機能を紹介していきたいと思います。 ※macOS版にて紹介していきます。 基本設定 まずは基本的な設定からです。 言語を選択 エディタを好きな言語に変更できます。 ※日本語設定で紹介していきます。 設定 View > Command Palette > Configure Display Language > 言語を選択 > エディタを再起動 テーマを選択 自分の好きなテーマに変更できます。 設定 Code > 基本設定 > 配色テーマ setting.json 設定した項目はsetting.jsonに保存されます。 設定 Code > 基本設定 > 設定 > アイコンクリック おすすめの拡張機能 Project Manager(プロジェクトマネージャー) プロジェクト管理ができる拡張機能です。 使用したいプロジェクトを登録し、素早く開くことが可能になります。 これで毎回Finderから探す手間もなくなります、単一で開いてくれるのでパフォーマンスも良いです。 操作 登録したいプロジェクト開き保存します、開いたディレクトリをルートとして登録できます。 Live Server(ライブサーバー) エディタをブラウザに自動反映できる拡張機能です。 保存した際に自動でブラウザが更新されます。 次に紹介するLive Sass Compilerと合わせて使用もとてもおすすめです。 ※PHPファイルは対応していないようです。 操作 エディタ下部にあるGo Liveをクリックするだけで自動でブラウザが立ち上がります。 Live Sass Compiler(ライブサースコンパイラー) Sassのコンパイルができる拡張機能です。 ワンボタンで素早くコンパイルができ、ファイル保存時の自動コンパイルやにも対応しています。 他にもオプション設定を加えることで、追加機能や細かい調整が可能です。 設定 オプション設定はsetting.jsonに追記していきます。 Formats "liveSassCompile.settings.formats": [  {   "format": "compact",   "extensionName": ".css",   "savePath": "./css" } ], format コンパイル後のスタイルの形状を指定します。 nested expanded compact compressed extensionName 拡張子を指定します。 savePath 出力先を指定します。 ※ディレクトリが存在しない場合も自動生成してくれます。 Exclude List 除外したいファイルを指定できます。 "liveSassCompile.settings.excludeList": [ "**/node_modules/**", ".vscode/**", ".history/**" ], Autoprefix ベンダープレフィックスを出力できます。 ファイル保存時の自動出力にも対応しています。 また、どのくらい古いバージョンのブラウザに対応するかおおよその設定ができます。 ベンダープレフィックスの出力をオフにしたい場合は[]のみに設定します。 "liveSassCompile.settings.autoprefix": [   "last 2 versions",  "ie >= 11",  "Android >= 4",  "ios_saf >= 8" ], 操作 エディタ下部のWatch Sassをクリックするとコンパイルできます。 おすすめのエディタ機能 ここからはコーディングやプログラミングの入力が捗るエディタ機能を紹介していきます。 User Snippets(ユーザースニペット) 登録したコードを瞬時に呼び出せる機能です。 呼び出した後に指定した箇所へカーソルが移動するように設定できます、複数順番まで細かく指定可能です。 設定 Code > 基本設定 > ユーザースニペット 作成したい言語を選択すると自動でjsonファイルが生成されるので書き込んでいきます。 試しにHTMLのpictureタグを設定していきます。 "picture": {  "prefix": "pic",  "body": [   "<picture>",   "\t<source media=\"(min-width:768px)\" srcset=\"./img/$1.png\">",   "\t<img src=\"./img/sp/$1.png\" alt=\"$2\">",   "</picture>"  ] } ・prefix 呼び出し時のネームを入れます。 ・body 呼び出したいコードを書いていきます。 記述ルールはサンプルを参照して下さい。 $ + 数字でカーソルが移動される順番を指定できます、同じ数値にすると同時入力ができます。 操作 prefixに入力したネームを入力した後に、Enterキーで呼び出します。 Tabキーを押していくと、$ + 数字 で設定した順にカーソルを移動できます。 Emmet(エメット) VSCodeではデフォルトで使用できます。 上記で紹介した、ユーザースニペットと組み合わせて使用すれば、さらに効果を発揮できます。 キーマップ おなじみの人気エディタのショートカットキーが使えるようになります。 設定 Code > 基本設定 > キーマップ 設定をプロジェクトごとに分けたい場合  ワークスペース プロジェクトごとに設定を変更したいケースが出てくるかと思います、そんな時はワークスペースを使用して個別に設定を管理できます。 ※ワークスペースで保存すると、プロジェクトのルート直下にsetting.json隠しファイルが生成されます。 設定 Code > 基本設定 > 設定 > ワークスペース > アイコンクリック 以上がおすすめの設定でした、最後までご覧戴きありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】汎用的なsmooth scroll(2021年)

スムーススクロールを実装する際、どのような技術や手順で作れば良いかいつも迷ってしまうので、備忘録としてまとめます。この記事ではnpmパッケージやjQueryなどのライブラリは使わずに実装します。 作成するスクロール 「ページの先頭へ戻る」的なページ最上部へ戻るボタン ページ内リンク 使用する技術 Polyfill.io Element.scrollIntoView() window.scrollTo smooth srcollを標準APIで実現するには、IE11やSafari(Mac OS/iOS)が対応していないbehaviorオプションを使用するため、Polyfill.ioでsmoothscrollという項目を選択したバンドル(URL)を作成します。 【例】(他に必要なpolyfillがある場合は適宜選択してください。) https://polyfill.io/v3/polyfill.min.js?features=smoothscroll 実装 ページ最上部へ戻るボタン const scrollToTop = () => { const anchorButtons = document.querySelectorAll('.js-scroll-to-top'); if(anchorButtons) { anchorButtons.forEach((button) => { toTop(button); }) } const toTop = (button) => { button.addEventListener('click', (event) => { // a要素のデフォルトの挙動をキャンセル。 // button[type="button"]の場合は不要です。 event.preventDefault(); window.scrollTo({ top: 0, behavior: "smooth" }); }); } } scrollToTop(); ページ内リンク const scrollToId = () => { const anchorButtons = document.querySelectorAll('.js-scroll-to-id'); if(anchorButtons) { anchorButtons.forEach((button) => { toIdElement (button); }) } const toIdElement = (button) => { // アンカーリンクのhrefから、移動先の要素を取得。 const targetId = anchor.getAttribute('href'); const target = document.querySelector(targetId); button.addEventListener('click', (event) => { // a要素のデフォルトの挙動をキャンセル。 event.preventDefault(); target.scrollIntoView({ behavior: "smooth", }); }); } } scrollToId();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript テキストアニメーション備忘録

はじめに JavaScriptでテキストアニメーションを実装してみたので、忘れないようにメモ程度に残しておきます。 CSSに関しては書かないので、JavaScriptのみの紹介になります。 かなりわかりにくいと思いますが、個人のメモ程度なのでご了承ください。 何度も投稿を続けて、わかりやすい記事が書けるように頑張ります。 JavaScriptコード説明 HTMLコード <h1 class='title'>ABC</h1> JavaScriptコード document.addEventListener("DOMContentLoaded", function () { const el = document.querySelector(".title"); const str = el.innerHTML.trim().split(""); el.innerHTML = str.reduce((acc, curr) => { curr = curr.replace(/\s+/, "&nbsp;"); return `${acc}<span class="char">${curr}</span>`; }, ""); }); 一行目でDOMがロードされた時にイベントが発火するようにする。 "title"というクラスを持つ要素をelに代入する。 elに対してinnerHTMLでelのHTML要素を取得し、trim()で全てのスペースを取り除き、split("")で文字列を一文字ずつ分割したものをstrに代入する。 innerHTMLでelのHTML要素に、先ほど一文字ずつに分割したそれぞれに対して"char"というクラスを付与したspanタグを挿入していく。HTML内の半角スペースを検知した場合、 という特殊文字に変換する。 accuは累積した結果、currは現在の文字を表す。 以上の流れを簡単に表すと ABCを取得 →前後のスペースを取り除いた上で"A", "B", "C"に分割 →<h1 class='title'><span class="char">A</span>BC</h1> →<h1 class='title'><span class="char">A</span><span class="char">B</span>C</h1> →<h1 class='title'><span class="char">A</span><span class="char">B</span><span class="char">C</span></h1> あとはCSSでcharクラスが付与された時に働くアニメーションを設定すれば完成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CDNからスクリプトが読めなくて困らないように考えてみた

はじめに CDNからスクリプトを読み込むようにしてて、CDNに障害が発生した場合 複数候補指定できたら解決するんじゃね? というハナシ ざっくり方法 スクリプトの候補を複数準備しておく 第1候補から繰り返す 1. 候補が存在するか確認する 2. 存在する場合、SCRIPTタグとして追加して終了 サンプル 構成 localhost:8082 │ index.html ├─test1 ├─test2 │ hello.js └─test3 hello.js URL http://localhost:8082/index.html 本体 http://localhost:8082/test1/hello.js 第1候補のスクリプト(存在しない) http://localhost:8082/test2/hello.js 第2候補のスクリプト http://localhost:8082/test3/hello.js 第3候補のスクリプト ソース hello.js const hello = () => { alert("Hello, world!"); } "Hello, world!"というダイアログを表示するhello関数のみ! index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>スクリプトを読み込むサンプル</title> <script> /** * スクリプトを読み込む * @param {string} src 読み込むソース * @return 読み込み結果 */ const loadScript = (src) => { // ソースの存在チェック const request = new XMLHttpRequest(); request.open("GET", src, false); request.send(null); // ソースが存在した場合、スクリプトタグを追加 if (request.status === 200) { let head = document.getElementsByTagName("head")[0]; let script = document.createElement("script"); script.src = src; head.appendChild(script); return true; } return false; }; // スクリプトのソース一覧 const srcArray = [ "http://localhost:8082/test1/hello.js", "http://localhost:8082/test2/hello.js", "http://localhost:8082/test3/hello.js" ]; // ソースの配列を先頭から、読み込めるまで読み込んでいく for (let i = 0; i < srcArray.length; i++) { if (loadScript(srcArray[i])) { console.log("Loaded script: " + srcArray[i]); break; } } window.onload = function () { hello(); }; </script> </head> <body> <button onclick="hello();">hello</button> </body> </html> 表示時とhelloボタン押下時に、読み込んだスクリプトのhello関数を実行する サンプルを実行 画面 表示時 "Hello, world!"というダイアログが表示されている helloボタン押下時 "Hello, world!"というダイアログが表示されている コンソール 1行目のワーニングは、XMLHttpRequestを使って同期でリクエストを送るのは非推奨なので表示 2行目のエラーは、第1候補のスクリプトが存在しないため表示 3行目のログは、第2候補のスクリプトが読み込まれたという表示 かんそう 思いつきで書いたので、サンプルをそのまま使うのは厳しい… 折角なのでメモの代わりに記事として残しておきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptにおけるデザインパターン3(振舞い系)

デザインパターンを整理する デザインパターンを次の3つに分けて考えます 作成系デザインパターン (コンストラクター、ファクトリー、シングルトンなど) 構造系デザインパターン (デコレータ、ファサードなど) 振舞い系デザインパターン (メディエータ、オブザーバーなど) 振舞い系デザインパターン オブジェクト間の通信を改善または合理化することに重点を置いています。 メディエーターパターン メディエーターパターンは、オブジェクトのグループがどのように相互作用するかをカプセル化することにより、オブジェクトのグループに対する中央権限を提供します。 // https://github.com/pkellz/devsage/blob/master/DesignPatterns/Mediator.js より function Member(name) { this.name = name this.chatroom = null } Member.prototype = { send: function (message, toMember) { this.chatroom.send(message, this, toMember) }, receive: function (message, fromMember) { console.log(`${fromMember.name} to ${this.name}: ${message}`) } } function Chatroom() { this.members = {} } Chatroom.prototype = { addMember: function (member) { this.members[member.name] = member member.chatroom = this }, send: function (message, fromMember, toMember) { toMember.receive(message, fromMember) } } const chat = new Chatroom() const bob = new Member('Bob') const john = new Member('John') const tim = new Member('Tim') chat.addMember(bob) chat.addMember(john) chat.addMember(tim) bob.send('Hey, John', john) john.send("What's up, Bob", bob) tim.send('John, are you ok?', john) // 結果 // // Bob to John: Hey, John // John to Bob: What's up, Bob // Tim to John: John, are you ok? 注目して欲しいのは、この例でBobとJohnあるいはJohnとTimなどが直接やりとりしているのではなく、Chatroom(メディエーター)の中でやりとりしていることです。そうすることで、結果にあるようにBob to JohnやJohn to Bobなど、誰と誰がやりとりをしているかをChatroom(メディエーター)で監視できているということです。 そのため、メディエーターに処理が集中してパフォーマンスが低下するとリスクもあります。 オブザーバーパターン Learning JavaScript Design Patterns より オブザーバーは、オブジェクト (サブジェクトと呼ばれる) がそれに依存するオブジェクト (オブザーバー) のリストを維持し、状態の変更を自動的に通知するデザイン パターンです。 function Subject() { this.observers = [] // array of observer functions } Subject.prototype = { subscribe: function (fn) { this.observers.push(fn) }, unsubscribe: function (fnToRemove) { this.observers = this.observers.filter((fn) => { if (fn != fnToRemove) return fn }) }, fire: function () { this.observers.forEach((fn) => { fn.call() }) } } const subject = new Subject() function Observer1() { console.log('Observer 1 Firing!') } function Observer2() { console.log('Observer 2 Firing!') } subject.subscribe(Observer1) subject.subscribe(Observer2) subject.fire() subject.unsubscribe(Observer1) subject.fire() // 結果 // // Observer 1 Firing! // Observer 2 Firing! // Observer 2 Firing! オブザーバーパターンはメディエーターのように中央に権限を集中させるのとは異なり、SubjectとObserverと呼ばれるオブジェクトに処理を分担します。 Subjectは、subjectにObserverを登録(subscribe)、または登録の解除(unsubscribe)、登録されているObserverへ通知を担当。 Obseverは、通知を受けた後の機能を担当。 機能を明確に切り分けることで、コード管理と再利用の可能性を改善できます。 参考文献 Learning JavaScript Design Patterns 関連記事 JavaScriptにおけるデザインパターン1(作成系) JavaScriptにおけるデザインパターン2(構造系)  おわりに Javascriptにおけるデザインパターンを学ぶためには、O'Reillyの Learning JavaScript Design Patternsを読むのがいいと思うのですが、理解するのが難しく感じました。 なので今回、Learning JavaScript Design Patternsを読む前準備として、いくつかのデザインパターンに絞って、個人的に概念の理解にしっくりきた時の文言やコードを記事にしました。 新しい概念に出会った時、毎回理解するのにとても苦労しますが、だからこそやりがいを感じ、飽きることなく続けることができるのだと思います。 人に伝える技術も磨いてさらに良い記事も書けるように頑張っていきたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneとOutlookを連携してスケジュール管理をする#02

経緯 kintoneのOutlookを連携してスケジュール管理をしたい。 けど検索して出てくる記事が古いため、アレンジしてなるべく最新のものに対応する。 要するに「Outlook連携 - kintoneからOutlookスケジュールを登録しよう!!」のOutlook連携をほぼサンプルのまま使っていたのだけど、先日急に動かなくなったので最新化対応したいということ。 やりたいこと MSAL v2 に対応してkintoneとOutlookのスケジュールを連携させたい。 kintone UI Component v1 対応したUIを構築したい。 FullCalendar.js を導入してカレンダー表示させたい。 参考サンプル こちらの2つのサンプルを参考にOutlook連携カスタマイズを行います。 1. Outlook連携 - kintoneからOutlookスケジュールを登録しよう!! 2. クイックスタート: PKCE 対応の承認コード フローを使用して JavaScript SPA 内でユーザーをサインインさせ、アクセス トークンを取得する 今回(本記事)のゴール AzureADで認証しサインインする。 記事一覧 #01.ボタンを表示 #02.サインイン ← 当記事 #03.サインアウトとボタン表示制御 AzureADの設定 「クイックスタート: PKCE 対応の承認コード フローを使用して JavaScript SPA 内でユーザーをサインインさせ、アクセス トークンを取得する」の記事を見て環境を構築し、サンプルを実際に動かしてサインインできることを確認します。 認証の設定でプラットフォームは「シングルページ アプリケーション」でリダイレクトURIを設定します。 サンプルを動かして認証を確認するのであれば「 http://localhost:3000/ 」が設定されていれば大丈夫です。 kintoneに実装する際は、アプリのURLを追加で設定します。 MSAL v2 では暗黙的な許可を使用しないので、チェックはしないでください。 ※MSAL v1 では両方にチェックを入れます。 サンプルを動かし、サインインボタンを押してサインインできれば環境構築はOKです。 サンプルはAzureADのクイックスタートから入手すると諸々設定済みなので確認が簡単です。 サインイン処理を実装する Microsoftのサンプルをそのまま動くように実装します。 javascript https://unpkg.com/kintone-ui-component/umd/kuc.min.js https://js.cybozu.com/jquery/3.3.1/jquery.min.js https://alcdn.msauth.net/browser/2.13.1/js/msal-browser.js ← ★追加 authConfig.js ← ★追加 authPopup.js ← ★追加 buttonSettings.js ui.js css buttons.css ボタンに処理を登録 サインインボタン作成時にボタン押下時の処理を登録します。 実行する処理は authPopup.js の signIn() です。 ui.js // ボタンの表示情報を取得 let BS = window.buttonSettings; // カスタマイズのメイン処理 let uiService = { setting: { lang: {}, i18n: {}, ui: {} }, data: { ui: {}, }, // 初期処理 init: function () { // ログインユーザーの言語設定を取得 this.setting.lang = kintone.getLoginUser().language || 'ja'; this.setting.i18n = this.setting.lang in BS.lang ? BS.lang[this.setting.lang] : BS.lang.en; this.setting.ui = BS.setting.ui; }, // ボタン表示設定 uiNotSignCreateForIndex: function (kintoneHeaderSpace) { if (typeof kintoneHeaderSpace === 'undefined') { return; } // サインイン前のボタン表示 this.data.ui.HeaderNotSigned = document.createElement('div'); // ボタンを作成 this.data.ui.btnSignIn = this.createButton(this.setting.ui.buttons.signIn, this.setting.i18n.button); // サインインボタン押下時の処理を登録 this.data.ui.btnSignIn.addEventListener('click', function (event) { authPopupService.signIn(); }); // ボタンを表示用に格納 this.data.ui.HeaderNotSigned.appendChild(this.data.ui.btnSignIn); kintoneHeaderSpace.appendChild(this.data.ui.HeaderNotSigned); }, // ボタンを作成 createButton: function (setting, lang) { if (typeof setting === 'undefined' || !setting) { return null; } let uiButton; let text = lang ? lang[setting.text] || setting.text || '' : setting.text || ''; let type = setting.type; let className = setting.className ? setting.className : ''; uiButton = new Kuc.Button({ text: text, type: type, className: className }); return uiButton; }, }; // 画面表示時イベント kintone.events.on('app.record.index.show', function (event) { // 初期処理 uiService.init(); // サインインボタン表示 uiService.uiNotSignCreateForIndex(kintone.app.getHeaderSpaceElement()); }); 認証プログラムの実装 Microsoftのサンプルをそのまま使います。 やることは認証情報を設定して loginPopup をしているだけです。 authConfig.js の redirectUri には実装するkintoneアプリのURLを設定してください。 ※AzureADのリダイレクトURIにも同じURLを設定してください。 authConfig.js const msalConfig = { auth: { clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", authority: "https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", redirectUri: "https://xxx.cybozu.com/k/xxx/", }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false, }, system: { loggezrOptions: { loggerCallback: (level, message, containsPii) => { if (containsPii) { return; } switch (level) { case msal.LogLevel.Error: console.error(message); return; case msal.LogLevel.Info: console.info(message); return; case msal.LogLevel.Verbose: console.debug(message); return; case msal.LogLevel.Warning: console.warn(message); return; } } } } }; const loginRequest = { scopes: ["User.Read"] }; authPopup.js は基本そのままいいですが、ログインに成功したことを確認するためコンソールにメッセージを出力するよう追加しています。 authPopup.js const myMSALObj = new msal.PublicClientApplication(msalConfig); let username = ""; let authPopupService = { // ログイン情報による制御 selectAccount: function() { const currentAccounts = myMSALObj.getAllAccounts(); if (currentAccounts.length === 0) { return; } else if (currentAccounts.length > 1) { console.warn("Multiple accounts detected."); } else if (currentAccounts.length === 1) { username = currentAccounts[0].username; console.log(username); } }, //サインイン後の処理 handleResponse: function(response) { if (response !== null) { username = response.account.username; // 認証の成功を確認 console.log("succsess"); console.log(username); } else { this.selectAccount(); } }, // サインイン signIn: function() { myMSALObj.loginPopup(loginRequest) .then(this.handleResponse) .catch(error => { console.error(error); }); }, } 実装できたらボタンを押下して確認 kintone画面のボタンを押下するとログイン画面が表示されます。 ログインを行い、認証に成功するとコンソールにメッセージ(ログインユーザーのメールアドレス)が表示されることが確認できます。 認証まで成功すれば、あとはその後にやりたい処理を加えていくだけです。 次回 サインアウトとボタン表示制御
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsでLINE Botを作るときの複数リプライメモ #linedc

どこが配列になるっけ... がよく忘れるのでメモ まずは通常 return client.replyMessage(event.replyToken, { type: 'text', text: responseMsg //実際に返信の言葉を入れる箇所 }); 2件リプライ return client.replyMessage(event.replyToken, [{ type: 'text', text: '1件目' }, { type: 'text', text: '2件目' } ]); 一度のリプライは5件まで 現時点だと6件以上はエラーになります。 return client.replyMessage(event.replyToken, [{ type: 'text', text: '1件目' }, { type: 'text', text: '2件目' }, { type: 'text', text: '3件目' }, { type: 'text', text: '4件目' }, { type: 'text', text: '5件目' } ]); } テキストと画像を同時にリプライ 画像のメッセージオブジェクト詳細はこちらを参考にしましょう。 return client.replyMessage(event.replyToken, [{ type: 'text', text: '1件目' }, { type: 'image', originalContentUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png', previewImageUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png' } ]); さらにスタンプも同時にリプライ スタンプのメッセージオブジェクト詳細はこちらを参考にしましょう。 return client.replyMessage(event.replyToken, [{ type: 'text', text: '1件目' }, { type: 'image', originalContentUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png', previewImageUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png' }, { type: 'sticker', packageId: '446', stickerId: '1988' } ]); さらにFlex Messageも同時にリプライ ここまでくるとJSONがぐちゃぐちゃですが一応できます。 JSON崩れるとバグるのでFLEX MESSAGE SIMULATORの利用はほぼマストかも。 return client.replyMessage(event.replyToken, [{ type: 'text', text: '1件目' }, { type: 'image', originalContentUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png', previewImageUrl: 'https://i.gyazo.com/ff363c0d05710b9803349c9e5423cce1.png' }, { type: 'sticker', packageId: '446', stickerId: '1988' }, { "type": "flex", "altText": "this is a flex message", "contents": { "type": "bubble", "body": { "type": "box", "layout": "vertical", "contents": [ { "type": "button", "action": { "type": "postback", "label": "ぼたん1", "data": "button1", "displayText": "ほげほげ" }, "gravity": "top" }, { "type": "button", "action": { "type": "postback", "label": "ぼたん2", "data": "button2", "displayText": "ふがふが" } } ] } } } ]); まとめ 複数メッセージは5件までなら送れますが、Flex Messageを使った瞬間にJSON地獄になるのでご利用は計画的に
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インタープリタを作る その19

概要 インタープリタを作ってみた。 avrインタープリター書いてみた。 avrの命令調べてみた。 命令セット Command Operands Operation Description Flags Cycles Opcode ADC Rd, Rr Rd←Rd + Rr + C Add two registers with carry --HSVNZC 1 0001 11rd dddd rrrr ADD Rd,Rr Rd←Rd + Rr Add two registers --HSVNZC 1 0000 11rd dddd rrrr ADIW Rh:Rl, K Rh:Rl←Rh:Rl + K Add immediate to Word (0 ≤ K ≤ 63) ---SVNZC 2 1001 0110 KKdd KKKK AND Rd,Rr Rd←Rd • Rr Logical AND two registers ---SVNZ-, V cleared 1 0010 00rd dddd rrrr ANDI Rd, K Rd←Rd • K Logical AND with immediate (16 ≤ d ≤ 31) ---SVNZ-, V cleared 1 0111 KKKK dddd KKKK ASR Rd C←Rd(0), Rd(6…0) ←Rd(7…1), Rd(7) ←Rd(7) Arithmetic shift right ---SVNZC 1 1001 010d dddd 0101 BCLR s SREG(s) ←0 Clear bit in status register SREG(s) 1 1001 0100 1sss 1000 BLD Rd,b Rd(b) ←T Load bit in register from T -T------ 1 1111 100d dddd 0bbb BRBC s,k if(SREG(s) = 0) PC←PC + k + 1 Branch if status register flag cleared -------- 1,2* 1111 01kk kkkk ksss BRBS s,k if(SREG(s) = 1) PC←PC + k + 1 Branch if status register flag set -------- 1,2* 1111 00kk kkkk ksss BRCC k if(C=0) then PC←PC + k + 1 Branch if carry cleared, Same as brbc 0,k and brsh -------- 1,2* 1111 01kk kkkk k000 BRCS k if(C=1) then PC←PC + k + 1 Branch if carry set, Same as brbs 0,k and brlo -------- 1,2* 1111 00kk kkkk k000 BREAK For on-chip debug only -------- 1 1001 0101 1001 1000 BREQ k if(Z=1) then PC←PC + k + 1 Branch if equal, Same as brbs 1,k -------- 1,2* 1111 00kk kkkk k001 BRGE k if(S=0) then PC←PC + k + 1 Branch if greater or equal (signed), Same as brbc 4,k -------- 1,2* 1111 01kk kkkk k100 BRHC k if(H=0) then PC←PC + k + 1 Branch if half-carry flag cleared, Same as brbc 5,k -------- 1,2* 1111 01kk kkkk k101 BRHS k if(H=1) then PC←PC + k + 1 Branch if half-carry flag set, Same as brbs 5,k -------- 1,2* 1111 00kk kkkk k101 BRID k if(I=0) then PC←PC + k + 1 Branch if interrupt disabled, Same as brbc 7,k -------- 1,2* 1111 01kk kkkk k111 BRIE k if(I=1) then PC←PC + k + 1 Branch if interrupts enabled, Same as brbs 7,k -------- 1,2* 1111 00kk kkkk k111 BRLO k if(C=1) then PC←PC + k + 1 Branch if lower, unsigned, Same as brbs 0,k and brcs -------- 1,2* 1111 00kk kkkk k000 BRLT k if(S=1) then PC←PC + k + 1 Branch if less than (signed), Same as brbs 4,k -------- 1,2* 1111 00kk kkkk k100 BRMI k if(N=1) then PC←PC + k + 1 Branch if minus, Same as brbs 2,k -------- 1,2* 1111 00kk kkkk k010 BRNE k if(Z=0) then PC←PC + k + 1 Branch if not equal, Same as brbc 1,k -------- 1,2* 1111 01kk kkkk k001 BRPL k if(N=0) then PC←PC + k + 1 Branch if plus, Same as brbc 2,k -------- 1,2* 1111 01kk kkkk k010 BRSH k if(C=0) then PC←PC + k + 1 Branch if same or higher, unsigned, Same as brbc 0,k and brcc -------- 1,2* 1111 01kk kkkk k000 BRTC k if(T=0) then PC←PC + k + 1 Branch if T flag cleared, Same as brbc 6,k -------- 1,2* 1111 01kk kkkk k110 BRTS k if(T=1) then PC←PC + k + 1 Branch if T flag set, Same as brbs 6,k -------- 1,2* 1111 00kk kkkk k110 BRVC k if(V=0) then PC←PC + k + 1 Branch if overflow flag is cleared, Same as brbc 3,k -------- 1,2* 1111 01kk kkkk k011 BRVS k if(V=1) then PC←PC + k + 1 Branch if overflow flag is set, Same as brbs 3,k -------- 1,2* 1111 00kk kkkk k011 BSET s SREG(s) ←1 Set bit in status register SREG(s) 1 1001 0100 0sss 1000 BST Rr,b T←Rr(b) Bit store from register to T -T------ 1 1111 101d dddd 0bbb CALL k PC←k; Stack←PC + 2; SP←SP–2 Direct subroutine call. 0≤k≤64K -------- 4 1001 010k kkkk 111k kkkk kkkk kkkk kkkk CBI P, b IOP ←0 Clear bit in I/O register, only for 0≤P≤31 -------- 2 1001 1000 PPPP Pbbb CBR Rd, K Rd←Rd•K Clear bit(s) in register, only for 16≤d≤31 ---SVNZ-, V cleared 1 As per ANDi with K Complemented CLC C←0 Clear carry flag, Same as bclr 0 -------C 1 1001 0100 1000 1000 CLH H←0 Clear half-carry flag, Same as bclr 5 --H----- 1 1001 0100 1101 1000 CLI I←0 Clear global interrupt flag (disable interrupts), Same as bclr 7 I------- 1 1001 0100 1111 1000 CLN N←0 Clear negative flag, Same as bclr 2 -----N-- 1 1001 0100 1010 1000 CLR Rd Rd←Rd ⊕ Rd Clear register, Same as eor Rd, Rd ---SVNZ-, Z set; S,V,N cleared 1 0010 01Dd dddd DDDD (DDDDD=ddddd) CLS S←0 Clear signed flag, Same as bclr 4 ---S---- 1 1001 0100 1100 1000 CLT T←0 Clear T flag, Same as bclr 6 -T------ 1 1001 0100 1110 1000 CLV V←0 Clear overflow flag, Same as bclr 3 ----V--- 1 1001 0100 1011 1000 CLZ Z←0 Clear zero flag, Same as bclr 1 ------Z- 1 1001 0100 1001 1000 COM Rd Rd←Rd or Rd←$FF – Rd One’s complement (inversion) ---SVNZC, V cleared, C set 1 1001 010d dddd 0000 CP Rd, Rr Rd – Rr Compare --HSVNZC 1 0001 01rd dddd rrrr CPC Rd,Rr Rd – Rr – C Compare with Carry --HSVNZC 1 0000 01rd dddd rrrr CPI Rd, K Rd – K Compare with immediate, 16≤ d ≤ 31 --HSVNZC 1 0011 KKKK dddd KKKK CPSE Rd,Rr if(Rd=Rr) PC←PC + 2 (or 3) Compare, skip if equal. -------- 1,2, 3† 0001 00rd dddd rrrr DEC Rd Rd←Rd – 1 Decrement register ---SVNZ- 1 1001 010d dddd 1010 EOR Rd,Rr Rd←Rd ⊕ Rr Exclusive OR two registers ---SVNZ-, V cleared 1 0010 01rd dddd rrrr FMUL Rd, Rr R1:R0 ← Rd * Rr Multiply unsigned 1.7 fractional number by another. 16 ≤ d ≤ 23, 16 ≤ r ≤ 23 ------ZC 2 0000 0011 0ddd 1rrr FMULS Rd, Rr R1:R0 ← Rd * Rr Multiply signed 1.7 fractional number by another. 16 ≤ d ≤ 23, 16 ≤ r ≤ 23 ------ZC 2 0000 0011 1ddd 0rrr FMULSU Rd, Rr R1:R0 ← Rd * Rr Multiply 1.7 fractional signed number (Rd) by 1.7 fractional unsigned number (Rr). 16 ≤ d ≤ 23, 16 ≤ r ≤ 23 ------ZC 2 0000 0011 1ddd 1rrr ICALL PC←Z; Stack←PC + 1; SP←SP–2 Indirect call to Z -------- 3 1001 0101 0000 1001 IJMP PC←Z Indirect Jump to Z -------- 2 1001 0100 0000 1001 IN Rd, P Rd←IO[P] Load an I/O Location to Register -------- 1 1011 0PPd dddd PPPP INC Rd Rd←Rd + 1 Increment register ---SVNZ- 1 1001 010d dddd 0011 JMP k PC ← k Jump to address anywhere in program memory. (0 ≤ k ≤ 4M) -------- 3 1001 010k kkkk 110k kkkk kkkk kkkk kkkk LD Rd, W Rd←M[W] Load Indirect (Y or Z case) -------- 2 1000 000d dddd W000 LD Rd, X Rd←M[X] Load Indirect (X case) -------- 2 1001 000d dddd 1100 LDD Rd,W+ q Rd←M[W+q] Load Indirect with Displacement (Y or Z only) -------- 2 10q0 qq0d dddd Wqqq LD Rd, W+ Rd←M[W]; W←W+1 Load Indirect with Postincrement (Y or Z) -------- 2 1001 000d dddd W001 LD Rd, X+ Rd←M[X]; X←X+1 Load Indirect with Postincrement (X) -------- 2 1001 000d dddd 1101 LD Rd, -W W←W-1; Rd←M[W] Load Indirect with Pre-decrement (Y or Z) -------- 2 1001 000d dddd W010 LD Rd, -X X←X-1; Rd←M[X] Load Indirect with Pre-decrement (X) -------- 2 1001 000d dddd 1110 LDI Rd, K Rd←K Load Immediate, 16 ≤ d ≤ 31 -------- 1 1110 KKKK dddd KKKK LDS Rd, k Rd←M[k] Load Direct from SRAM, 0≤k≤65535 -------- 2 1001 000d dddd 0000 kkkk kkkk kkkk kkkk LPM R0←PM[Z] Load program memory, Z contains a byte address. Least significant bit of Z selects low byte of the program word (if 0) or high byte (if 1) -------- 3 1001 0101 1100 1000 LPM Rd, Z Rd←PM[Z] As above, destination is Rd -------- 3 1001 000d dddd 0100 LPM Rd, Z+ R0←PM[Z] Z←Z+1 As above, destination is Rd. Z is incremented -------- 3 1001 000d dddd 0100 LSL Rd C←Rd(7); Rd(7…1) ←Rd(6…0); Rd(0) ←0 Logical Shift Left, Same as add Rd,Rd --HSVNZC 1 0000 11Dd dddd DDDD (DDDDD=ddddd) LSR Rd C←Rd(0); Rd(6…0) ←Rd(7…1); Rd(7) ←0 Logical Shift Right ---SVNZC, N←0 1 1001 010d dddd 0110 MOV Rd, Rr Rd←Rr Move between registers -------- 1 0010 11rd dddd rrrr MOVW Rd, Rr Rd+1:Rd← Rr+1:Rr Copy one register pair to another. d=0,2,4…30; r=0,2,4…30 -------- 1 0000 0001 dddd rrrr MUL Rd, Rr R1:R0 ← Rd * Rr Multiply two 8-bit unsigned numbers. (Unsigned result) ------ZC 2 1001 11rd dddd rrrr MULS Rd, Rr R1:R0 ← Rd * Rr Multiply two 8-bit signed numbers. 16 ≤ d ≤ 31, 16 ≤ r ≤ 31 ------ZC 2 0000 0010 dddd rrrr MULSU Rd, Rr R1:R0 ← Rd * Rr Multiply 8-bit signed number (Rd) by 8-bit unsigned number (Rr). 16 ≤ d ≤ 23, 16 ≤ r ≤ 23 ------ZC 2 0000 0011 0ddd 0rrr NEG Rd Rd←$00 – Rd Two’s complement (negation) --HSVNZC 1 1001 010d dddd 0001 NOP No operation -------- 1 0000 0000 0000 0000 OR Rd,Rr Rd←Rd or Rr Logical OR two registers ---SVNZ-, V cleared 1 0010 10rd dddd rrrr ORI Rd, K Rd←Rd or K Logical OR with immediate, 16 ≤ d ≤ 31 ---SVNZ-, V cleared 1 0110 KKKK dddd KKKK OUT P, Rr IO[P] ←Rr Store Register to I/O Location -------- 1 1011 1PPr rrrr PPPP POP Rd SP←SP+1; Rd←STACK Pop register from stack -------- 2 1001 000d dddd 1111 PUSH Rr STACK←Rr; SP←SP–1 Push register on Stack -------- 2 1001 001r rrrr 1111 RCALL k PC←PC + k + 1; Stack←PC + 1; SP←SP–2 Relative Subroutine Call, -2048 ≤ k ≤ 2047 -------- 3 1101 kkkk kkkk kkkk RET SP←SP+2; PC←Stack Subroutine return -------- 4 1001 0101 0000 1000 RETI SP←SP+2; PC←Stack Return from interrupt (and enable interrupts) I-------, I is set 4 1001 0101 0001 1000 RJMP k PC←PC + k + 1; Relative Jump, -2048 <= k <= 2047 -------- 2 1100 kkkk kkkk kkkk ROL Rd C←Rd(7); Rd(7…1) ←Rd(6…0); Rd(0) ←C Rotate left through carry, Same as adc Rd,Rd --HSVNZC 1 0001 11Dd dddd DDDD (DDDDD=ddddd) ROR Rd C←Rd(0); Rd(6…0) ←Rd(7…1); Rd(7) ←C Rotate right through carry ---SVNZC 1 1001 010d dddd 0111 SBC Rd, Rr Rd←Rd – Rr – C Subtract two registers with carry --HSVNZC 1 0000 10rd dddd rrrr SBCI Rd, K Rd←Rd – K – C Subtract immediate with carry, 16 ≤ d ≤ 31 --HSVNZC 1 0100 KKKK dddd KKKK SBI P, b IOP ←1 Set bit in I/O register, 0<=P<=31 -------- 2 1001 1010 PPPP Pbbb SBIC P, b if(IOP = 0) PC←PC + 2 (or 3) Skip if bit in I/O register is cleared, 0<=P<=31 -------- 1,2, 3† 1001 1001 PPPP Pbbb SBIS P, b if(IOP = 1) PC←PC + 2 (or 3) Skip if bit in I/O register is set, 0<=P<=31 -------- 1,2, 3† 1001 1011 PPPP Pbbb SBIW Rh:Rl, K Rh:Rl←Rh:Rl–K Subtract immediate from word, 0 ≤ K ≤ 63 ---SVNZC 2 1001 0111 KKdd KKKK SBR Rd, K Rd←Rd or K Set bit(s) in register, 16 ≤ d ≤ 31, same as ori ---SVNZ-, V cleared 1 0110 KKKK dddd KKKK SBRC Rr, b if(Rr(b) = 0) PC←PC + 2 (or 3) Skip if bit in register is cleared -------- 1,2, 3† 1111 110r rrrr 0bbb SBRS Rr, b if(Rr(b) = 1) PC←PC + 2 (or 3) Skip if bit in register is set -------- 1,2, 3† 1111 111r rrrr 0bbb SEC C←1 Set carry flag, Same as bset 0 -------C 1 1001 0100 0000 1000 SEH H←1 Set half-carry flag, Same as bset 5 --H----- 1 1001 0100 0101 1000 SEI I←1 Set global interrupt flag (enable interrupts). Instruction following sei will always be executed before any pending interrupts are handled. Same as bset 7 I------- 1 1001 0100 0111 1000 SEN N←1 Set negative flag, Same as bset 2 -----N-- 1 1001 0100 0010 1000 SER Rd Rd←$FF Set register, 16 ≤ d ≤ 31, Same as LDI Rd, $FF -------- 1 1110 1111 dddd 1111 SES S←1 Set signed flag, Same as bset 4 ---S---- 1 1001 0100 0100 1000 SET T←1 Set T flag, Same as bset 6 -T------ 1 1001 0100 0110 1000 SEV V←1 Set overflow flag, Same as bset 3 ----V--- 1 1001 0100 0011 1000 SEZ Z←1 Set zero flag, Same as bset 1 ------Z- 1 1001 0100 0001 1000 SLEEP Sleep. Sets CPU in sleep mode defined by the MCU control register -------- 1 1001 0101 1000 1000 SPM PM[Z] ←R1:R0 Store program memory – see instruction reference manual for details. -------- Varies 1001 0101 1110 1000 ST W, Rr M[W] ←Rr Store Indirect (Y or Z cases) -------- 2 1000 001r rrrr W000 ST X, Rr M[X] ←Rr Store Indirect (X case) -------- 2 1001 001r rrrr 1100 ST W+, Rr M[W] ←Rr; W←W+1 Store Indirect with Postincrement (Y or Z) -------- 2 1001 001r rrrr W001 ST X+, Rr M[X] ←Rr; X←X+1 Store Indirect with Postincrement (X) -------- 2 1001 001r rrrr 1101 ST -W, Rr W←W-1; M[W] ←Rr Store Indirect with Pre-decrement (Y or Z) -------- 2 1001 001r rrrr W010 ST -X, Rr X←X-1; M[X] ←Rr Store Indirect with Pre-decrement (X) -------- 2 1001 001r rrrr 1110 STD W+q,Rr M[W+q] ←Rr Store Indirect with Displacement (Y or Z only) -------- 2 10q0 qq1r rrrr Wqqq STS k, Rr M[k] ←Rr Store Direct To SRAM -------- 2 1001 001r rrrr 0000 kkkk kkkk kkkk kkkk SUB Rd, Rr Rd←Rd - Rr Subtract two registers --HSVNZC 1 0001 10rd dddd rrrr SUBI Rd, K Rd←Rd – K Subtract immediate, 16 ≤ d ≤ 31 --HSVNZC 1 0101 KKKK dddd KKKK SWAP Rd Rd(7…4) ←Rd(3…0); Rd(3…0) ←Rd(7…4) Swap nibbles (i.e. high 4 bits is exchanged with low 4 bits) -------- 1 1001 010d dddd 0010 TST Rd Rd←Rd • Rd Test for zero or minus, same as And Rd, Rd ---SVNZ-, V cleared 1 0010 00Dd dddd DDDD (DDDDD=ddddd) WDR Watchdog reset -------- 1 1001 0101 1010 1000
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rspecでボタンをクリック→へんじがない…ただのもじれつのようだ…

はじめに よくあるアコーディオンメニュー(※)を実装し、その挙動テストをRspecで書いていたときに困ったことについて、記事にしたいと思います。 ※ここでいうよくあるアコーディオンメニューとは、「+ボタン」を押すと、メニューが展開し、「+」が「ー」に変化するようなものであり、JavaScriptを使って実装しています。 発生した問題 最初に書いたテストは次のとおりです。 describe "アコーディオンメニューのテスト" do it "メニューが展開すること" do  #「+」、「ー」はFontAwesomeを使って実装 find(".fa-plus").click expect(page).to have_css ".fa-minus" end end 勘のいい方はこの段階でお気づきかと思いますが、Rspecを実行したところ、次のようなエラーが出力されました。 Failure/Error: expect(page).to have_css ".fa-minus" expected to find css ".fa-minus" but there were no matches 「ーボタン」が見つからないと言われているようです。 それなら、「+ボタン」がクリックされた後は、どんな状態になっているのか気になったため、試しにテストを次のように書き換えて、Rspecを実行したところ、テストが通りました。 describe "アコーディオンメニューのテスト" do it "メニューが展開すること" do find(".fa-plus").click expect(page).to have_css ".fa-plus" end end どうやら「+ボタン」をクリックした後も、「ーボタン」に変化するのではなく、「+ボタン」のままになっているようです。 要するに何も変化していないということです。 解決方法 「js: true」を追加しました。 describe "アコーディオンメニューのテスト" js: true do it "メニューが展開すること" do  #「+」、「ー」はFontAwesomeを使って実装 find(".fa-plus").click expect(page).to have_css ".fa-minus" end end さいごに 今回のミスは、JavaScriptを使っている箇所のテストに「js: true」を書いていなかったという、知っている人から見れば、当たり前のようなことですが、エラー文が出るわけでもないので、私は発見に時間がかかりました。 ちなみに、本当の闘いは、このあと「js: true」を使えるようにするために、Gemを入れたり、Docker環境だったのでDockerfileを変更したりしなければならないということだったのですが、この記事の趣旨から外れるので、そちらは割愛します。 Rspecを使い始めたばかりの方の、気づきになれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む