20220114のJavaScriptに関する記事は14件です。

Vue.js + Server-Sent Eventsで画像をリアルタイム取得してみる

概要 サーバーから能動的にデータを送信するHTTP通信方法であるServer-Sent Events(SSE)を利用して画面上の画像を都度差し替えて表示する仕組みを作ってみました。 今回は画像送信を挙げていますが、特にチャット文言やセンサーデータなどリアルタイムでやり取りさせるものでよりイメージが出来るかと思います。 導入 画面側 下記のコードをvue.js内のmethodsに書き込めばおおよそ完了。 EventSourceにはリアルタイム取得したいサーバー側のURIを書き込み、Cookieも有効にしたい場合はコンマ区切りで{ withCredentials: true }を追加すればOK。 今回はサーバーから取得した画像ファイルをそのまま出すだけなのでevent内のdataをそのまま変数に格納する作りになります。 <script> methods: { getImage () { let evtSource = new EventSource('/get_image', { withCredentials: true }) evtSource.addEventListener('message', event => { this.imgSrc = event.data }, false) } } </script> vueファイルの全体像としては下記のイメージ。 display.vue <template> <div> <img :src="imgSrc"/> </div> </template> <script> export default { data () { return { imgSrc: null } }, created: function () { this.getImage() }, methods: { getImage () { let evtSource = new EventSource('/get_image', { withCredentials: true }) evtSource.addEventListener('message', event => { this.imgSrc1 = event.data }, false) } } } </script> サーバー側 とりあえずランダムで画像URL送り込む感じで。 Image.java @GetMapping(value = "/get_image", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<Object> getImage() {    String[] imageArray = { "https://2.bp.blogspot.com/-27IG0CNV-ZE/VKYfn_1-ycI/AAAAAAAAqXw/fr6Y72lOP9s/s800/omikuji_kichi.png", "https://3.bp.blogspot.com/-vQSPQf-ytsc/T3K7QM3qaQI/AAAAAAAAE-s/6SB2q7ltxwg/s1600/omikuji_daikichi.png", "https://4.bp.blogspot.com/-qCfF4H7YOvE/T3K7R5ZjQVI/AAAAAAAAE-4/Hd1u2tzMG3Q/s1600/omikuji_kyou.png" }; Random rand = new Random(); return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> imageArray[rand.nextInt(imageArray.length)]; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】qerySelectorによるDOMの取得

document.querySelector / document.querySelectorAllで要素を取得する document.querySelectorとdocument.querySelectorAllの違い document.querySelector 一致する要素のうち、先頭の1件を取得する idを指定する場合、document.getElementById()で取得するほうが高速である document.querySelectorAll 一致する要素のリストを取得する セレクター セレクター 説明 例 (*) 全ての要素を取得 document.querySelectorAll('*'); (#id) 指定したIDの要素を取得 document.querySelector('#sample-id'); (.class) 指定したクラス名の要素を取得 document.querySelectorAll('.sample-className'); (タグ名) 指定したタグ名の要素を取得 document.querySelectorAll('li'); (複数指定) 指定したいずれかのセレクターに合致する要素をすべて取得 document.querySelectorAll('#sample-id,.sample-className,li'); (parent > child) parent要素の子要素のchildを取得 document.querySelector('ul > li'); (prev + next) prev要素の直後に存在するnext要素を取得 document.querySelector('div + ul'); (prev + siblings) prev要素以降のsiblings兄弟要素を取得 document.querySelector('div ~ span'); [attr] 指定した属性を持つ要素を取得 document.querySelector('[data-attr]'); [attr=value] 属性がvalue値に等しい要素を取得 document.querySelector('[data-attr="123"]'); [attr^=value] 属性がvalueから始まる値を持つ要素を取得 document.querySelector('[data-attr^="12"]'); [attr$=value] 属性がvalueで終わる値を持つ要素を取得 document.querySelector('[data-attr$="23"]'); [attr*=value] 属性がvalueを含む値を持つ要素を取得 document.querySelector('[data-attr*="2"]'); [selector1][selector2][selectorx] 複数の属性フィルタすべてにマッチする要素を取得 document.querySelector('div#main[data-attr*="2"]'); (:checked) チェックボックス・ラジオボタンのチェック済み要素を取得 document.querySelectorAll('input[type="checkbox"]:checked')
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript【 応用力が身につく!実践トレーニング 】 動画集

JavaScript【応用力が身につく!実践トレーニング】 JavaScript/jQueryを使っていますが「コードを学習」することではなく 「 応用力 」「 創り上げる力 」 を学べるようにしてるのがポイントです。 自己紹介 ジーズアカデミー学校長(デジタルハリウッドでも教鞭をとる)山崎と申します。 ジーズアカデミーは開校6年目のデジタルハリウッドが運営する「起業家エンジニア養成スクール(卒業生が6年で69社起業し総資金調達額80億5,620万円と卒業生が頑張っている学校)」です。 今回、私の授業(初級者向け)で応用力を鍛えるためのサポート動画でYoutube配信したものをまとめました。 全国のプログラミング初学者・初級者の皆さんの底上げになればと思い公開させていただきます。必ず「基礎を学んだあと」に、以下動画をやり切っていただければ理解が深まります。 応用実践トレーニングの内容 内容は「基礎を学んだ」レベルに合わせています。 JavaScriptの「超基礎」のところはプロゲートなどで見ていただくと良いかと思います。そういった教材で「自分で考えて作れるようにならなかった人」が対象です。 「変数・分岐処理・繰り返し処理・関数・オブジェクト...」を応用できるようにするための教材として作りました。 また「 デジタルハリウッド / ジーズアカデミー / 大学 / 大学院 」で私の講義動画を見たことがある人はその追加講義として見ていただければと思います。 ※他の学校、提携校の皆さんもご活用ください! 「学び方・作り方・考え方」全て揃っています! ◆「効率よく学ぶためのポイントを紹介」準備編 サムネ1 サムネ2 タイトル 動画? 「効率よく学ぶ3つのポイント!」 https://youtu.be/-oq87SQZKfg 「正しい時間の使い方」 https://youtu.be/AdjP8pYa70sg Visual Studio Code おススメ便利機能 https://youtu.be/XQ8P51rc1Cg ◆「小さいアプリを沢山作る」トレーニング編 「変数・配列・繰り返し・オブジェクト...」の理解と応用能力を上げるトレーニング サムネ1 サムネ2 タイトル 動画? 「抽選アプリ」を作って楽しく学ぶ!(サンプルあり) https://youtu.be/V5KCKbBo000 「Todoアプリ」作って楽しく学ぶ!(サンプルあり) https://youtu.be/PfV0Cus6jhw 「席決めアプリ」作って楽しく学ぶ!(サンプルあり) https://youtu.be/aDRDRd_BR2s 「アラーム機能を作る」作って楽しく学ぶ! https://youtu.be/OgV2cAg3Q8E 「Book検索アプリ」Ajaxと作り方を学ぶ(サンプルあり) https://youtu.be/Yo0gz7DN2xM 「Chatアプリ(Firebase RDB version9 対応) https://youtu.be/v2ILwppYXhY 「Chatアプリ前編(Firebase Firestore version9 対応) https://youtu.be/Z6-0CpG619s 「Chatアプリ後編(Firebase Firestore version9 対応) https://youtu.be/40Z9kK8kO60 jQueryわかるなら「JavaScriptも理解できる!」 https://youtu.be/5ENyHWkClMI JSONが「完璧」に理解できる動画! https://youtu.be/67lgE8o-lwA ◆アルゴリズムとは?を理解するトレーニング編 サムネ1 サムネ2 タイトル 動画? 「めちゃ解る!アルゴリズム授業1」(サンプルあり) https://youtu.be/5hApch5oV3E 「めちゃ解る!アルゴリズム授業2」(サンプルあり) https://youtu.be/LqTn957uSb4 ◆クラスを理解し「ライブラリを作る」思考をトレーニング編(中級) サムネ1 サムネ2 タイトル 動画? 『クラス入門』丁寧に解説!(サンプルあり) https://youtu.be/r6jJpBZkRRc 『ライブラリの作り方!』~jQueryを作ってみる~ https://youtu.be/UPNQRrVTAgo ◆JSで「File API」を使い画像を操作するトレーニング編 サムネ1 サムネ2 タイトル 動画? 基本:画像サイズ取得・画像プレビュー(サンプルあり) https://youtu.be/Zi1Kvsd_R_g 応用:画像サイズ取得・画像プレビュー(サンプルあり) https://youtu.be/g3Drrzu6HkQ ◆ビジュアルプログラミング「p5.js」を知る!トレーニング編 ビジュアルプログラミング「p5.js」を使ってみます。 お題として、すみっコぐらし風の「ネコ」をプログラミング描きならが慣れましょう。 サムネ1 サムネ2 タイトル 動画? 前編:すみっコぐらし風プログラミング「ネコを描く」 https://youtu.be/Mo9Y1-Q_D2w 後編:すみっコぐらし風プログラミング「ネコを描く」 https://youtu.be/gOBWomSWaxA ◆「Chromeデベロッパーツール・全て学べる」トレーニング編 HTML/CSS/JavaScripを使った制作には「Chromeデベロッパーツール」は必須スキルです! デザインの調整、他サイトの構造見たり、エラーの確認、デバッグ等で良く使います。 サムネ1 サムネ2 デベロッパーツールは奥が深いので、最初は「#1,#2」だけをおススメします タイトル 動画? #1「 Elements/Console 」 https://youtu.be/PjZyPfXdJFA #2「 デバッガ― 」 https://youtu.be/TXi5g4J17ds #3「 ブラウザ機能 (中級レベル)」 https://youtu.be/DsHhKs9V03o #4「 Lighthouse(中級レベル) 」 https://youtu.be/srayKfhg5Ho #5「 セキュリティ&ネットワーク機能(中級レベル) 」 https://youtu.be/Sn1oaEJwt0k #6「 CSSアニメーション検証機能(中級レベル) 」 https://youtu.be/zICHhUf6-Nw ※この段階で100%理解はいりません。50%くらいの理解で「そんな機能あるのか」でOKです。  必要になれば自然と使いだします。その時に覚えていけばOKです。 ◆アプリを作る上での考え方編 最初「こんなの作ろうかな~」「あんなの作りたい!」とあると思いますが、 最初にどうやって初めていいか分からないのではないでしょうか? 作り始める前の頭を整理し、どのように作っていくかを解説している動画になります。 タイトル 動画? 初めてアプリを作る時どう進めればいいの?(授業内の切り抜き) https://youtu.be/DYRdF7KNyqM ライブラリの調べ方&使い方 https://youtu.be/ShQJTcxXDmY ◆プログラミング初学者「絶対やるエラー10選」エラー対策に サムネ1 サムネ2 タイトル 動画? プログラミング初心者『 エラー 10選 (前編)』これで解決 https://youtu.be/Iy1uvBrPCIY プログラミング初心者『 エラー 10選 (後編)』これで解決 https://youtu.be/CnODCflPMgY ◆ 関係ないけどおススメ動画 タイトル 動画? パソコンを知らない私が「エンジニア」になれたポイントお話します https://youtu.be/Hh15HcpKtYM ハーバード大、プログラミング講座を見て驚いた! https://youtu.be/7Qs84P0EoB8 データベース? #1「 基本から解説」(プログラミング必須スキル) https://youtu.be/Er4JbQXyTxM 個人開発したWebサービス「 1年運営してみた 」 https://youtu.be/NbganVQJgmU Linuxコマンド 超入門「ブラウザだけで学べます」 https://youtu.be/-7ZDeEYgrh8 【山崎メソッドの動画、役立ちましたか?】 山崎メソッドは「楽しく、作りながら学び、小さな成功体験を積む」を重視しています! - SNSでの拡散 - 学校で「使わせてもらってます」 - 応援メッセージ など、お願いできればと思います!! ※必須ではありませんが今後のやる気につながります(#^^#) 学校等での講義依頼も受けてますので気軽にお声がけください また、基礎から私たちから学びたいと言う人がいれば、ぜひ学校へ来てください。 今後も講義動画増えたら、こちらを更新していきます。 ブックマークしていただければ幸いです。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】Instagram Graph APIを使用してWEBページに正方形の画像を埋め込む

Instagram Graph APIを使用してInstagramの画像をwebページに埋め込む際に、少し手間取ったので備忘録として。 実現したいこと Instagram Graph APIを利用してInstagramから取得した画像をwebページに埋め込み、正方形のグリッド状に配置したい。 実装 Instagramのプロアカウント作成からwebページへの埋め込みまではこちらを参考に行った。 実装後に起きた問題 画像が表示されない。 画像をクリックしても投稿に飛ばない。 取得された画像サイズが正方形ではないのでレイアウトが崩れる。 原因 画像が表示されない。 phpファイル内のGraph APIのバージョンが最新ではなかった。 目的のInstagramアカウントの投稿数が、Graph APIで取得する数(javascriptファイルのphoto_lengthの値)より少なかった。 javascriptファイル内のphpファイル指定がうまく動作しなかった。 画像をクリックしても投稿に飛ばない。 投稿へのリンクの値であるpermalinkを取得していなかった。 取得された画像サイズが正方形ではないのでレイアウトが崩れる。 対策を後述。 修正点 画像が表示されない。 phpファイルの$instagram_api_url内のGraph APIのバージョンを最新のものに書き換える。 「取得する画像の数 ≦ 目的のアカウントの投稿の数」にする。 javascriptファイル内のphpファイル指定を相対パスから絶対パスに変更。 画像をクリックしても投稿に飛ばない。 phpファイルの$query内の、media{値(省略)}の値の部分にpermalinkを追加。 javascriptファイルのphotos +=内の、<li>と<img>の間に「<a href="' + gallery_data[i].permalink + '" target="_blank">」を追加(閉じタグも忘れずに) 取得された画像サイズが正方形ではないのでレイアウトが崩れる。 こちらのサイトを参考に<li>タグを正方形にして、中に入れる画像をobject-fit: cover;で拡大表示。 まとめ 以上で、webサイト内にInstagramの画像をレスポンシブな正方形で配置することができた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptでRPG#15

こんにちは 今回は、前回の続きで石の採掘を仕上げていきます 石の採掘『いいえ』 では、main.jsのスペースキーの文章のなかにこちらをいれてください main.js //石の採掘の質問 if(talk_number==14){ map_r=4; } そしたら、main.jsの中のメインループの中にこれを入れ・変更もしてください ※変更→石の採掘のイベントスタートのif文のところです main.js //石の採掘のイベントスタート if(mapdate[pl["y"]/32+9][pl["x"]/32+10]==3&&system["current_item"]==1&&map_r==0){ talk_number=14; ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText(talk[talk_number],16,544); } //石の採掘の『はい』と『いいえ』の選択肢の『はいver』 if(map_r==4&&map_l==1){ talk_number=5; ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("はい←",16,544) ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("いいえ",16,624) } //石の採掘の『はい』と『いいえ』の選択肢の『いいえver』 if(map_r==4&&map_l==0){ talk_number=5; ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("はい",16,544) ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("いいえ←",16,624) } //メインループ終了 このような感じになったら次に、上の方(メインループの中)のこの文章を探してください main.js //Enterで次へを挿入 if(map_r==1){ ctx.font=system["ctx_font2"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("上下矢印キーとEnterで選択",400,624) } こちらをこのように変更してください main.js //Enterで次へを挿入 if(map_r==1||map_r==4){ ctx.font=system["ctx_font2"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("上下矢印キーとEnterで選択",400,624) } そしたら、上・下矢印キーが押されたときのところをこのように変更してください main.js if(e.which==38){ //上キーが押されたとき pl_g_up=true; if(talk_number==2)talk_number++; if(map_r==1||map_r==4)map_l++; } ...(中略) if(e.which==40){ //下キーが押されたとき pl_g_down=true; if(talk_number==2)talk_number++; if(map_r==1||map_r==4)map_l++; } では、次にこの文章を探してください(エンターキーのところにあります) main.js //家に入る(いいえ) if(map_r==1&&map_l==0){ map_r=0; } こちらをこのように変更してください main.js //家に入る・石の採掘(いいえ) if((map_r==1||map_r==4)&&map_l==0){ map_r=0; } これで、石の採掘の『いいえ』の部分が完成しました 石の採掘『はい』 では次に『はい』の部分を作っていきます まず、石の画像の変数を作っていきます system変数をこのように変更し、ブラウザの自動時の処理をこのように変更してください main.js const system = { "ctx_font":"32px monospace", "ctx_font2":"16px monospace", "talk-1":0, "mapchip_size":32, "pl_animation":0, "mapchip":"", "pl1":"", "stone_pickel":"", "stone":"", "item_box":0, "item_box_i":0, "current_item":0 } main.js //ブラウザ起動時の処理 window.onload = function(){ system["mapchip"] = new Image(); system["mapchip"].src = 'https://raw.githubusercontent.com/sugoruru/rurukun3-save/main/tile-set4.png';//マップタイルの読み込み system["stone_pickel"] = new Image(); system["stone_pickel"].src = 'https://raw.githubusercontent.com/sugoruru/rurukun3-save/main/d-tile.png';//石のつるはしの読み込み system["stone"] = new Image(); system["stone"].src = 'https://raw.githubusercontent.com/sugoruru/rurukun3-save/main/item-2.png';//石の読み込み system["pl1"] = new Image(); system["pl1"].src = 'https://raw.githubusercontent.com/sugoruru/rurukun3-save/main/p-tile-set1.png';//キャラクタータイルの読み込み setInterval(function() {main_loop()},20);//「main_loop」を20mm秒ごとに呼び出し //世界のマップ mapdate=[...world]; } そしたら、石のつるはしの入手と同時に石をアイテム欄に表示されるようにしましょう この文章を探してください main.js //石のツルハシ表示 if(pl["stone_pickel"]==1&&map_r==3){ ctx.drawImage(system["stone_pickel"],0,0,32,32,0,64,64,64); } この文章を探せたら、こちらに変更してください main.js //石のツルハシ表示 if(pl["stone_pickel"]==1&&map_r==3){ ctx.drawImage(system["stone_pickel"],0,0,32,32,0,64,64,64); ctx.drawImage(system["stone"],0,0,32,32,64,64,64,64); } そして、今気づいたのでこちらもこうしてください ※アイテム欄の表示しているときに装備中のアイテムが表示されるのを防ぎます こちらの文章を探してください main.js //現在持っているアイテムを表示する枠の表示 if(system["item_box"]==0){ ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 0, 100, 44); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 44, 5, 100); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 144, 100, 5); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(95, 44, 5, 100); ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("装備中",0,30); } if(system["current_item"]==1){ ctx.drawImage(system["stone_pickel"],0,0,32,32,0,40,114,114); } こちらをこのように変更してください main.js //現在持っているアイテムを表示する枠の表示 if(system["item_box"]==0){ ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 0, 100, 44); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 44, 5, 100); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(0, 144, 100, 5); ctx.fillStyle = "rgba(" + [0, 0, 0, 1] + ")"; ctx.fillRect(95, 44, 5, 100); ctx.font=system["ctx_font"]; ctx.fillStyle = "rgba(" + [255, 255, 255, 1] + ")"; ctx.fillText("装備中",0,30); } //石のつるはしを装備しているときに表示する if(system["current_item"]==1&&map_r==0){ ctx.drawImage(system["stone_pickel"],0,0,32,32,0,40,114,114); } では、今回はこれで終わります できない等の事があればコメントで教えて下さい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Font Awesome6のCSSからアイコンのリストを生成する

はじめに  この度Font Awesomeのアイコンピッカーを作成しGithubで公開しました。  その際の少しおもしろい使用方法を使ったので、こちらに残しておきたいと思います。   Font Awesomeのアイコンピッカーは「itsjavi/fontawesome-iconpicker」が有名どこのようですが、2018年に更新が止まり、使用を試みましたがうまく動作しないことが確認できました。 itsjavi/fontawesome-iconpicker  こちらを改良して使用するてもあったのですが、今回の目的としては、npmが使いたいわけでもなく、SVGデータが欲しいわけでも、フレームワーク上やCMSに乗せるわけでもないので、大した機能が必要なわけではなく。  そもそもFont Awesome4までしか対応してなく、javascript内にあるアイコンリストから表示を作っているようで、これを更新して使うのは一苦労になりそうな感じです。  2022年になり、そろそろFont Awesome6もBeta版から正式バージョンになりそうです。 自分で作るしかないかなと思い立ちライブラリ風にまとめてみました。  使用したい&使い方を知りたい人は、直下のダウンロードから使ってください。 Qiita(本記事)では後で思い出せるように参考にした文献を貼りながらCSSからアイコンリストを作る技術解説をしたいと思います。  Font Awesome6からWordPress用のアイコンピッカープラグインが公式で配布されていますので、WordPressで使いたい方は、公式プラグインのほうが出来がいいですのでお勧めです。 Font Awesome Wordpressプラグイン ダウンロード&マニュアル こちらからどうぞ 手段(本編) Font AwesomeにはCSS版と、JavaScript版があります。 どちらのファイルから一覧を作ってもよかったのですが、 CSSから作成する方が面白そうだったのでCSSから作ることにしました。 動作確認環境・依存関係 Chrome バージョン: 96.0.4664.110(Official Build) (64 ビット) bootstrap 5.1.3 Font Awesome Free 6.0.0-beta3 document.styleSheets JavaScriptからCSSファイルの中身を扱うには、document.styleSheetsを使用します。 document.styleSheets[n].cssRulesの中にCSSファイルの内容がCSSStyleRuleの形式で格納されています。 CSSStyleRule内の定義は、Element.styleでの書き方と同じです。 const targetCssName = "ファイル名.css"; let targetSheet = styleSheets.filter((styleSheet) => styleSheet.href !== null && styleSheet.href.endsWith(targetCssName))[0]; こんな感じで、CSSを1つに絞ります。 CORS問題の回避 CORSで指定した(CDNなど)CSSファイルのrulesはGoogleChromeでは参照できないようです。 Font AwesomeのCSSファイルをダウンロードしてきて使用すれば解決できます。 それだと使いにくいので、CSSをAjaxで持ってきてDOMにコピー function loadCSSCors(stylesheet_uri) { var _xhr = globalThis.XMLHttpRequest; var has_cred = false; try {has_cred = _xhr && ('withCredentials' in (new _xhr()));} catch(e) {} if (!has_cred) { console.error('CORS not supported'); return; } var xhr = new _xhr(); xhr.open('GET', stylesheet_uri); xhr.onload = function() { xhr.onload = xhr.onerror = null; if (xhr.status < 200 || xhr.status >= 300) { console.error('style failed to load: ' + stylesheet_uri); } else { var style_tag = document.createElement('style'); style_tag.appendChild(document.createTextNode(xhr.responseText)); document.head.appendChild(style_tag); const targetSheet = document.styleSheets[document.styleSheets.length-1]; targetSheet.disabled = true; draw(targetSheet); } }; xhr.onerror = function() { xhr.onload = xhr.onerror = null; console.error('XHR CORS CSS fail:' + styleURI); }; xhr.send(); } 一度読み込んだCSSをもう一度わざわざ読み込んでいるので、無駄ではありますが…… 新しくCSSが読み込まれると、一番最後に追加されるので const targetSheet = document.styleSheets[document.styleSheets.length-1]; と書けば、StyleSheetが特定できます。 WEBフォントの読み込みエラーが出るのと、CSSが2重適用されてしまうので、無効にしておきます。 targetSheet.disabled = true; cssRulesの中から、Font Awesomeのフォント情報だけを取り出す Font Awesomeのフォントを指定している部分は fontawesome.css .class::before { content: "文字コード" } になっているので、 const members = Array.from(targetSheet.rules).filter(v => v instanceof CSSStyleRule && v.style.content !== ""); contentがあるルールだけを取り出します。 CSSStyleRuleではないオブジェクトも含まれているので、エラーしないように取り除きます。 画面に書き出す function draw(targetSheet){ const members = Array.from(targetSheet.rules).filter(v => v instanceof CSSStyleRule && v.style.content !== ""); const drawEl = document.body; let zFlag = false; members.forEach(function(v,k) { if(members[k-1] !== void 0 && members[k-1].style.content == v.style.content) return; const iconName = v.selectorText.replace("::before", "").replace(".",""); const i = document.createElement("i"); i.classList.add(zFlag ? 'fa-brands' : 'fa-solid',iconName.split(', .')[0]); const btn = document.createElement('button'); btn.classList.add('btn','btn-outline-secondary', 'm-1'); btn.setAttribute('data-fapc-icon-name',iconName); btn.setAttribute('data-fapc-icon-type',zFlag ? 'fa-brands' : 'fa-solid'); btn.style.width = "3em"; btn.style.height = "3em"; drawEl .appendChild(btn).appendChild(i); if(iconName == "fa-z"){ zFlag = true; } }); } Font Awesome6は英文字1字の「A」fa-a~「Z」fa-zまでのアイコンが用意されていて、brandアイコンとの境目がちょうど、fa-zなので、fa-zが来たら次からbrandアイコン用のclassに切り替えています。 イベントを作ったりする ボタンにイベントを付けたり、受け取るinputを用意したりする。 この辺は、WEB上にたくさん知見があると思います。 宗教上の理由で記述方法が決まっている方もいると思います。 なので、今回は省略します。 完成 HTMLなどを書いて完成 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0-beta3/css/all.min.css"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script type="text/javascript"> function init(){ const targetCssName = "all.min.css"; let targetSheet = Array.from(document.styleSheets).filter((styleSheet) => styleSheet.href !== null && styleSheet.href.endsWith(targetCssName))[0]; if(targetSheet !== void 0 && targetSheet.href && !targetSheet.href.startsWith(window.location.origin)){ loadCSSCors(targetSheet.href); }else{ draw(targetSheet); } } function draw(targetSheet){ const members = Array.from(targetSheet.rules).filter(v => v instanceof CSSStyleRule && v.style.content !== ""); const drawEl = document.body; let zFlag = false; members.forEach(function(v,k) { if(members[k-1] !== void 0 && members[k-1].style.content == v.style.content) return; const iconName = v.selectorText.replace("::before", "").replace(".",""); const i = document.createElement("i"); i.classList.add(zFlag ? 'fa-brands' : 'fa-solid',iconName.split(', .')[0]); const btn = document.createElement('button'); btn.classList.add('btn','btn-outline-secondary', 'm-1'); btn.setAttribute('data-fapc-icon-name',iconName); btn.setAttribute('data-fapc-icon-type',zFlag ? 'fa-brands' : 'fa-solid'); btn.style.width = "3em"; btn.style.height = "3em"; drawEl .appendChild(btn).appendChild(i); if(iconName == "fa-z"){ zFlag = true; } }); } function loadCSSCors(stylesheet_uri) { var _xhr = globalThis.XMLHttpRequest; var has_cred = false; try {has_cred = _xhr && ('withCredentials' in (new _xhr()));} catch(e) {} if (!has_cred) { console.error('CORS not supported'); return; } var xhr = new _xhr(); xhr.open('GET', stylesheet_uri); xhr.onload = function() { xhr.onload = xhr.onerror = null; if (xhr.status < 200 || xhr.status >= 300) { console.error('style failed to load: ' + stylesheet_uri); } else { var style_tag = document.createElement('style'); style_tag.appendChild(document.createTextNode(xhr.responseText)); document.head.appendChild(style_tag); const targetSheet = document.styleSheets[document.styleSheets.length-1]; targetSheet.disabled = true; draw(targetSheet); } }; xhr.onerror = function() { xhr.onload = xhr.onerror = null; console.error('XHR CORS CSS fail:' + styleURI); }; xhr.send(); } document.addEventListener('DOMContentLoaded', init); </script> </head> <body> </body> </html> CSSからアイコンのリストを無事に作ることが出来ました。 たくさんありすぎる…… 公開しているライブラリでは アイコン検索(FontAwesomeでの英語名のみ) 除外機能 inputタグへの値渡し機能 ポップアップ(poper.js on bootstrap) などに対応しています。 ダウンロード&マニュアル(再掲) MITライセンスにて公開中です。 よかったら使ってみてください。 おわり(感想) CSSの要素を解析して、リストを作る方法を検証しました。 CORS問題などがなければかなり簡単にできることが分かりました。 あと、Array.filterって便利だなと最近多用しております。(いまさら) 今回の使おうと思っていた用途ではSolidのアイコンのみでいいのですが、 Font Awesome 6から、Regularのアイコンも一部無料で使えるようになっていますが、この方法だと対応できていません。 何かいい方法があればコメント欄などで教えていただければ嬉しいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[React]ボタン押下で動的にformを追加する

ざっくり説明 1年前に下書きしてたやつを掘り返した。 やり方は大まかにこんな感じ。 buttonをclickでformを追加 formの内容がchangeしたときに値をsetState コード書くよ 前提として ここから始まります。 import React from 'react'; class TaskForm extends React.Component { constructor(props){ super(props); this.state={ tasks: [ { task_name: "", start_datetime: "", end_datetime: "", task_memo: "", } ], }; } render() { return ( <div className="task-form"> <input type="text" placeholder="task_name" name="task_name" value={task.task_name} /> <input type="datetime-local" placeholder="start_datetime" name="start_datetime" value={task.start_datetime} /> <input type="datetime-local" placeholder="end_datetime" name="end_datetime" value={task.end_datetime} /> <textarea placeholder="task_memo" name="task_memo" value={task.task_memo} /> </div> ); } } export default TaskForm; 本題 button追加 render() { return ( <div className="task-form"> <input type="text" placeholder="task_name" name="task_name" value={task.task_name} /> <input type="datetime-local" placeholder="start_datetime" name="start_datetime" value={task.start_datetime} /> <input type="datetime-local" placeholder="end_datetime" name="end_datetime" value={task.end_datetime} /> <textarea placeholder="task_memo" name="task_memo" value={task.task_memo} /> <button type="button" onClick={() => this.addNewTask()}>+</button> </div> ); } addNewTask()記述 addNewTask(){ this.setState({ tasks: [...this.state.tasks, { task_name: "", start_datetime: "", end_datetime: "", task_memo: "" }] }); } map関数導入 render() { return ( <div className="task-form"> { this.state.tasks.map((task, index) => { return ( <div key={index}> <input type="text" placeholder="task_name" name="task_name" value={task.task_name} /> <input type="datetime-local" placeholder="start_datetime" name="start_datetime" value={task.start_datetime} /> <input type="datetime-local" placeholder="end_datetime" name="end_datetime" value={task.end_datetime} /> <textarea placeholder="task_memo" name="task_memo" value={task.task_memo} /> </div> ) }) } <button type="button" onClick={() => this.addTask()}>+</button> </div> ); } 入力した値を表示 onChange render() { return ( <div className="task-form"> { this.state.tasks.map((task, index) => { return ( <div key={index}> <input type="text" placeholder="task_name" name="task_name" value={task.task_name} onChange={(e) => {this.handleChange(e, index)}}/> <input type="datetime-local" placeholder="start_datetime" name="start_datetime" value={task.start_datetime} onChange={(e) => {this.handleChange(e, index)}}/> <input type="datetime-local" placeholder="end_datetime" name="end_datetime" value={task.end_datetime} onChange={(e) => {this.handleChange(e, index)}}/> <input type="url" placeholder="url" name="url" value={task.url} onChange={(e) => {this.handleChange(e, index)}}/> <textarea placeholder="task_memo" name="task_memo" value={task.task_memo} onChange={(e) => {this.handleChange(e, index)}}/> </div> ) }) } <button type="button" onClick={() => this.addTask()}>+</button> </div> ); } handleChange() handleChange(e, index){ this.state.tasks[index][e.target.name] = e.target.value; this.setState({tasks: this.state.tasks}); } 参考 1年前で不確かだけど外国人の方のYoutubeです。 react dynamic form とかで検索してたはず。 それっぽいのおいておきます。。。 参考にさせていただいた方すみません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C++,C#のコメントアウトテクニック

概要 下記のような記載が出来る言語で使えるコメントアウトのTips 使える言語の参照 main.cpp // 1行コメント /* 複数行コメント 複数行コメント */ 内容 複数行コメントを1文字で切り替える 先頭のスラッシュ(/)を消すと切り替えれる main.cpp //* 現在の 複数行コメントは コメントアウトされない //*/ /* 現在の 複数行コメントは コメントアウトされる //*/ 機能の切り替えを1文字で切り替える 上記のIF版で 先頭のスラッシュ(/)を消すと切り替えれる main.cpp //* Active Block /*/ Disable Block //*/ /* Disable Block /*/ Active Block //*/ まとめ C++er には多少有名なのでN番煎じではあるもののいろいろな言語で使えるので書いてみました。 C++では#if #endifで切り替えたりしますが、プリプロセッサで簡単に切り替える機能がない言語だと使いみちはありそうです。 後1文字切り替えなので楽ですが、可読性が良いとは言えないので過度な利用は控えたほうが良さそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript 「~ is read-only」エラー解決法

目的 「~ is read-only」エラーが出たので、解決法を調査する。 現状 show.jsのcreatePhraseListTableNodeからlib.jsの関数を呼び出して、 trNodeという変数で「trNode is read-only」というエラーが出ている。 show.js const PhrasesTable = createPhraseListTableNode(phraseList); lib.js const createPhraseListTableNode = (phraseList) => { const tableNode = document.createElement('table'); tableNode.setAttribute('id', 'phrase-list'); const theadNode = document.createElement('thead'); const tbodyNode = document.createElement('tbody'); const trNode = document.createElement('tr'); let thVals = ['単語', '意味', '']; for (let i = 0; i < thVals.length; i++) { const thNode = document.createElement('th'); thNode.innerText = thVals[i]; trNode.appendChild(thNode); } for (let phrase in phraseList) { trNode = createPhraseTrNode(phrase); tbodyNode.appendChild(trNode); } tableNode.appendChild(theadNode); tableNode.appendChild(tbodyNode); return tableNode; } const createPhraseTrNode = (phrase) => { const trNode = document.createElement('tr'); const contentTdNode1 = document.createElement('td'); contentTdNode1.innerText = phrase.content; const meaningTdNode = document.createElement('td'); meaningTdNode.innerText = phrase.meaning; const btnTdNode = document.createElement('td'); const btnNode = document.createElement('button') btnNode.value = "削除" btnTdNode.appendChild(btnNode); return trNode; } エラー内容 実際に調べてみるとこのエラーはJavascriptの厳密モードにおいて、割り当てられたグローバル変数やオブジェクトプロパティが読み取り専用であることを表している。 推測 読取専用の変数に対して代入しようとしている。 つまり今回は「trNode」という読取専用の変数に対して代入している場所が怪しい 「trNode」という変数に代入している場所を探すと、以下のような記述がある。 lib.js const createPhraseListTableNode = (phraseList) => { ... trNode = createPhraseTrNode(phrase); ... } 先頭で作成しているtrNodeという変数はthead作成の際に使用されている。その後tbodyを作成のループに入った際に代入しようとして先程のエラーが出たのではないかと考える。 // phraseListを tableにして返す const createPhraseListTableNode = (phraseList) => { const trNode = document.createElement('tr'); // theadの作成 for (let i = 0; i < thVals.length; i++) { const thNode = document.createElement('th'); trNode.appendChild(thNode); }  //tbodyの作成 for (let phrase in phraseList) { let bodyTrNode = createPhraseTrNode(phrase); tbodyNode.appendChild(bodyTrNode); } tableNode.appendChild(theadNode); tableNode.appendChild(tbodyNode); return tableNode; } 解決 thead作成とtbody作成の際に同じtrNodeという変数を使用していることが問題 - thead用とtbody用の変数に明確に分ける。 lib.js const createPhraseListTableNode = (phraseList) => { ... let thVals = ['単語', '意味', '']; // thead用のtrNode変数 const headTrNode = document.createElement('tr'); for (let i = 0; i < thVals.length; i++) { const thNode = document.createElement('th'); thNode.innerText = thVals[i]; headTrNode.appendChild(thNode); } for (let phrase in phraseList) { // tbody用のtrNode変数 let bodyTrNode = createPhraseTrNode(phrase); tbodyNode.appendChild(bodyTrNode); } tableNode.appendChild(theadNode); tableNode.appendChild(tbodyNode); return tableNode; } 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cropper.jsで加工した画像をAjaxでLaravelに送り保存する。

この記事では、Cropper.jsを利用し画像を加工したあとに、加工した画像をAjaxを通してLaravelに渡し、その画像を保存する方法を紹介します。 Cropper.jsは、ライブプレビューとカスタムアスペクト比をサポートしており、JavaScript / jQueryプラグインを画像のトリミングに利用するのに便利です。 事前準備 1. フォルダの作成 ファイルを保存する先のフォルダを作成します。 今回、コントローラで指定するフォルダは「storage/app/public/upload」です。 ファイルをアップロードして画像を切り取って保存を押すと、このフォルダに保存されます。 バックエンド側 2. ルーティング 次に下記のルーティングを設定してください。 routes/web.php Route::get('image-cropper','ImageCropperController@index'); Route::post('image-cropper/upload','ImageCropperController@upload'); 3. コントローラ 次に下記のようなコントローラを作成します。 app/Http/Controller/ImageCropperController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class ImageCropperController extends Controller { public function index() { return view('cropper'); } public function upload(Request $request) { $folderPath = storage_path('app/public/upload/'); // 保存先のパス $image_parts = explode(";base64,", $request->image); $image_type_aux = explode("image/", $image_parts[0]); // ファイルの型を取り出す(今回は使わない) $image_type = $image_type_aux[1]; // ファイルの型を取り出す(今回は使わない) $image_base64 = base64_decode($image_parts[1]); // 画像データとして取り出す $file = $folderPath . uniqid() . '.png'; // 保存に使うファイル名 file_put_contents($file, $image_base64); // ファイルを保存 return response()->json(['success'=>'success']); // JSONでレスポンスを返す } } フロントエンド側 3. ビュー 最後にお待ちかねのビューを用意します。 ここにCropper.jsの処理も記述します。 resources/views/cropper.blade.php <!DOCTYPE html> <html> <head> <title>Laravel Crop Image Before Upload using Cropper JS - LaravelCode</title> <meta name="_token" content="{{ csrf_token() }}"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha256-WqU1JavFxSAMcLP2WIOI+GB2zWmShMI82mTpLDcqFUg=" crossorigin="anonymous"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.css" integrity="sha256-jKV9n9bkk/CTP8zbtEtnKaKf+ehRovOYeKoyfthwbC8=" crossorigin="anonymous" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.js" integrity="sha256-CgvH7sz3tHhkiVKh05kSUgG97YtzYNnWt6OXcmYzqHY=" crossorigin="anonymous"></script> </head> <style type="text/css"> img { display: block; max-width: 100%; } .preview { overflow: hidden; width: 160px; height: 160px; margin: 10px; border: 1px solid red; } .modal-lg{ max-width: 1000px !important; } </style> <body> <div class="container"> <h1>Cropper.JSで加工した画像をAjaxでLaravelに送信</h1> <input type="file" name="image" class="image"> </div> <div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="img-container"> <div class="row"> <div class="col-md-8"> <img id="image" src="https://avatars0.githubusercontent.com/u/3456749"> </div> <div class="col-md-4"> <div class="preview"></div> </div> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">キャンセル</button> <button type="button" class="btn btn-primary" id="crop">保存</button> </div> </div> </div> </div> </div> </div> <script> var $modal = $('#modal'); var image = document.getElementById('image'); var cropper; $("body").on("change", ".image", function(e){ var files = e.target.files; var done = function (url) { image.src = url; $modal.modal('show'); }; var reader; var file; var url; if (files && files.length > 0) { file = files[0]; if (URL) { done(URL.createObjectURL(file)); } else if (FileReader) { reader = new FileReader(); reader.onload = function (e) { done(reader.result); }; reader.readAsDataURL(file); } } }); $modal.on('shown.bs.modal', function () { cropper = new Cropper(image, { aspectRatio: 1, viewMode: 3, preview: '.preview' }); }).on('hidden.bs.modal', function () { cropper.destroy(); cropper = null; }); $("#crop").click(function(){ canvas = cropper.getCroppedCanvas({ width: 160, height: 160, }); canvas.toBlob(function(blob) { url = URL.createObjectURL(blob); var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = function() { var base64data = reader.result; $.ajax({ type: "POST", dataType: "json", url: "image-cropper/upload", data: {'_token': $('meta[name="_token"]').attr('content'), 'image': base64data}, success: function(data){ $modal.modal('hide'); alert("success upload image"); } }); } }); }) </script> </body> </html> 最後に 以上の実装でAjaxを通してLaravelにCropper.jsで加工した画像を送れるはずです。 ぜひ試してみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】ある音楽ゲームのボーダー許容を計算する

某音ゲーでは、1,010,000点を上限に判定の善し悪しによってスコアが減少していく。 具体的にはすべてのノーツで最高評価をとれば1,010,000点となるが、それ以下の評価を取るとそのたびにスコアが減少する。 100万/総ノーツ数でそれぞれのノーツの基礎点が決まったのち、 評価によって以下のようにスコアへ影響する。 JUSTICE CRITICAL:基礎点×101% JUSTICE:基礎点×100% ATTACK:基礎点×50% MISS:基礎点×0% 計算式さえわかってしまえば、総ノーツ数とスコアから何個JUSTICEを出したかを計算することができる。 あくまでJUSTICEの数のみを計算するが、ATTACK は JUSTICE 51個分、MISS は JUSTICE 101個分となるので読み変えは可能。 以上を加味するとJUSTICE以下の数を算出する計算式は以下となる。 floor(総ノーツ数 * ((1010000 - スコア) / 10000)) floorは切り捨てを意味する。 //計算を行う関数 function Calc(notes, score) { //総ノーツ数とスコアを参照する const lost = Math.floor(notes * ((1010000 - score) / 10000)); return lost; //JUSTICEの数 }; //例 ノーツ数1311、スコア1009923点の場合、1311 * 0.0077(101 - 100.9923)を切り捨てして10という値が得られる。 //楽曲データを定義する const music = { notes: 1311, //総ノーツ数を設定 score: 1009923 //スコアを設定 }; const justice = Calc(music.notes, music.score); //総ノーツ数とスコアを渡す console.log("JUSTICEの数", justice); //例 JUSTICEの数 10 また、スコアの部分を1007500などにするとSSSボーダーなどを計算することもできる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】現在時刻を取得する

割と使うけど忘れやすいので、JavaScriptで現在時刻を取得する方法を備忘録としてメモしておく。 const date = new Date(); //現在時刻を取得 const y = date.getFullYear(), //西暦年 m = date.getMonth() + 1, //月  d = date.getDate(), //日 H = date.getHours(), //時 M = date.getMinutes(), //分 S = date.getSeconds(); //秒 console.log(y,m,d,H,M,S); //例 2022 1 14 3 10 30 他にもミリ秒を取得するなどもある。 あとは使う形式に応じて色々と整形する。 `${y}/${m}/${d}`; //例 2022/1/14 `${H}:${M}:${S}`; //例 3:10:30 0paddingなどと組み合わせると 2022/01/14 03:10:30などの表記もできる。 const m_pad = ( '00' + m ).slice( -2 ); //'00'とsliceの中身は桁数に応じて増減させる。今は2桁表示にさせたいので0は二つ、sliceの中は-2。 console.log(m_pad); //例 01
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Figma APIで特定File内の任意のFrame名を全てクリップボードにコピーする

@xrxoxcxox さんのcurlでやる方法ではなく、JavaScriptでやる方法です。 やりたいこと 下記のようなことを想定しています。 FigmaのFrame名を画面名やIDにしており、それをスプレッドシート等で管理(一覧化)するために、Figmaから対象のFrame名一覧を取得したい どうやるか DevToolsのConsoleを利用し、JavaScriptで取得する 手順 下記のような手順で実行します。 Figmaの該当ファイルを開く ⌘ + Option + I or Ctrl + Shift + I でDevToolsを開き、Consoleタブを開く 抽出したいFigmaのFrameを選択する 後述するコードをConsoleに貼り付けて実行する クリップボードに選択したFrame名がコピーされるので、それをスプレッドシートなどに貼り付ける let selection = figma.currentPage.selection; let frameNames = selection.map(n => n.name).join("\n"); copy(frameNames); ポイント 過去の記事でも書きましたが、FigmaではDevToolsを使えば、Figma APIをJavaScriptで扱って色々できます。 figma.currentPage.selection は「現在のページ」の「選択中」のレイヤーを意味します。 selection.map() では、上記で取得したレイヤーの配列に対し処理を行い、新しい配列として frameNames に格納します。 join("") は、配列に対し、その引数の文字列で区切った文字列を返してくれます。この場合は、\n という改行コードで区切るようにします。 console.log(selection.map(n => n.name)) // ["01. トップページ", "02. 会社概要", "03. お問い合わせ", "04. プライバシーポリシー"] console.log(selection.map(n => n.name).join("\n")) // .join("\n")で下記に変わる // 01. トップページ // 02. 会社概要 // 03. お問い合わせ // 04. プライバシーポリシー 最後のcopy()はDevToolsに用意されている関数で、これだけでクリップボードにコピーされます。 ※普通のWebページなどで実行しても使えません。 さらに応用 ひと手間加えて、対象のFrameのURLも取得してしまいましょう。 先にサンプルコードを載せます。 // FileのURLからファイル名までを手動でコピーする // ※下記はダミーのURL let fileURL = "figma://file/vkVHI0JG0CpE2cULt13eh7/Sample" let selection = figma.currentPage.selection; let frameNames = selection.map(n => { // Frameの名前 const name = n.name; // 前述したFileのURLと、FrameのNodeIDをくっつけるとこのFrameへのURLになる const url = `${fileURL}?node-id=${n.id}`; // 名前とURLをタブ区切り(`\t`)した文字列にする return `${name}\t${url}` }); // 名前とURLのセットを改行区切り(`\n`)にする let result = frameNames.join('\n'); // クリップボードにコピー copy(result); ポイント APIからFileのURLを直接取得できないので(たぶん)、Figmaでの Copy URL などでFileのURLを取得して文字列として格納する スプレッドシートのセルを列で分けて貼り付けるために、タブ区切りをする。そのために先程の改行コードのようにタブ区切りの \t を挟んだ文字列にする まとめ こんな感じでレイヤー(コードでいじる上ではNodeと呼びます)をどうこうできるので、また興味があればコードをカスタマイズして色々試してみてください! (例えば、選択したレイヤーではなく、第一階層のFrameにしたければ...など。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#p5js のプログラムを Window.js を使って動かしてみた手順のメモ(Mac を利用)

【注意】 とりあえず動作はさせられてますが、表示の問題が出ている状況で、原因はこれから調べるところです Twitter で @takawo さんが以下のツイートをされていたのを見て、自分も「p5.js のプログラムを Window.js で動かす」というのを試してみたのですが、その時の手順のメモです。 お?や?す?み pic.twitter.com/oYRHDL1u07— TAKAWO Shunsuke (@takawo) January 13, 2022 自分が試したものの結果 試した結果が以下のような感じで、ウィンドウの部分が少しおかしいです。 何か、試す手順でまずい部分があるのか、それとも... @takawo さんがツイートされてた Window.js で #p5js を動かせる話の件、公式ドキュメントを見つつ Mac で動かしてみた!(やり方がまずい部分があるのか、生成されたウィンドウがちょっとおかしいw)●Window.js | Processing with p5.js https://t.co/VvkfaL3WKu pic.twitter.com/O23fEGQdvN— you (@youtoy) January 13, 2022 試した手順 バイナリで配布されている実行ファイルのダウンロード ツイートに「Window.js」という名前が出ていたので、ググって以下の GitHubリポジトリにたどりつきました。 ●windowjs/windowjs: Window.js is an open-source Javascript runtime for desktop graphics programming.  https://github.com/windowjs/windowjs クイックスタートの部分を見ると、Windows用・Mac用のバイナリを配布していると書いてあったので、そのリンク先を見てみることに。 そこにあったバイナリのリンクのうち、Mac用のほうをクリックしてダウンロードしました。  ●Window.js | Download   https://windowjs.org/download ダウンロードについて、上記の公式ページに「ブラウザで警告がでるような話」が書かれており、その通りのメッセージが実際に出ました(ブラウザは Google Chrome)。 以下の画像にある、「破棄」と書かれたボタンの右の「^」という見た目の部分を押し、その後に表示される「継続」を押せばファイルをダウンロードできます。 ここでダウンロードした ZIPファイルを解凍すると、「windowjs」というファイルが 1つだけ出てきます。 これを適当なフォルダに置いて、ターミナルから ./windowjs というコマンドで実行すると、最終的には以下の画面が表示されるのですが、おそらくこの時点では警告がでて、実行をブロックされると思います。 原因は Apple公式の以下のページに書いてある「ノータリゼーション (公証) を受けていない未署名のソフトウェア」に該当するためです。  ●Mac で App を安全に開く - Apple サポート (日本)   https://support.apple.com/ja-jp/HT202491 これに対処するには、上記のページの「ノータリゼーションを受けていない App や未確認の開発元の App を開きたい場合」という部分に書かれた手順を実行するか、上記のページの下のほうに書いてる以下の手順を実行する必要があります。 自分は 2つ目のほう、具体的には以下を実行しました。  1)Finder上で「controlキー」を押しながら「windowjs」をクリック  2)表示されるメニューの中の「開く」を選択  3)さらにその後に出てくる警告画面で「開く」を選択 一度、これを行ってしまえば、次からは普通に実行できるようになります。 上記のファイルのダウンロードや実行がブロックされてしまう話は、公式のダウンロードページの中で、以下のように書かれていたりします。 p5.js のファイルを実行するための準備 先ほど、バイナリをダウンロードしたページの左の方を見ると、「Processing with p5.js」という記載があるので、それをクリックしてみました。 そうすると、以下のページが表示され、p5.js のプログラムを実行するためのコマンドが書いてありました。 $ out/src/windowjs.exe examples/p5.js -- examples/p5/simulate-recursive-tree.js コマンドの左端の部分(out/src/windowjs.exeの部分)は、先ほど試しに実行したコマンド(./windowjs)で置き換えができそうです。 あとは examples/p5.js の部分と -- examples/p5/simulate-recursive-tree.js の部分をどうすればいいか、という話が残ります。 それらを見ていきます。 コマンドの例が書かれた部分の下にある、「Implementation details」の部分で、「Support for p5.js in Window.js is provided via a loader in examples/p5.js that ...」という記載があり、 examples/p5.js の部分のリンク先が以下の GitHub のファイルになっていました。 ●windowjs/p5.js at main · windowjs/windowjs  https://github.com/windowjs/windowjs/blob/main/examples/p5.js その 403行目あたりを見ると、p5フォルダ内のファイルを読み込んだりしているようです。 https://github.com/windowjs/windowjs/blob/main/examples/p5.js#L403 GitHub のリポジトリ上にある「examples」以下の「p5.js」と「p5/p5.min.js」があれば、p5.js のプログラムを実行できるようでした(それと、プログラムを実行しているウィンドウにエラーメッセージが出るので「examples」以下に「p5/p5.ico」も置きました)。 話をまとめると、ファイルの構成は以下のようになり、その中の「p5test.js」が p5.js のプログラムという形です。 (余談ですが、当初はどのファイルが必要そうかを確かめず、とりあえず examples以下全体を使って動かしたりしてました) ここまで準備ができたら、あとは以下のコマンドでプログラムを実行するだけです。 $ ./windowjs ./examples/p5.js -- p5test.js 実行結果は、冒頭に掲載していたツイートのとおりです。 なお、その時に用いていたプログラムは以下です。 p5test.js function setup() { createCanvas(400, 400); frameRate(15); strokeWeight(15); pixelDensity(0.5); } function draw() { // background(220, 220, 220, 255 / 3); background(220, 220, 220); stroke(125, 125, 200, 100); line(mouseX, mouseY, pmouseX, pmouseY); stroke(200, 125, 200, 100); line(width - mouseX, height - mouseY, width - pmouseX, height - pmouseY); stroke(125, 200, 200, 100); line(width - mouseX, mouseY, width - pmouseX, pmouseY); stroke(200, 125, 125, 100); line(mouseX, height - mouseY, pmouseX, height - pmouseY); } これは、少し前に p5.js Web Editor上で作って動かしていたものを、そのまま流用しました。 先ほど動画をツイートしていた #p5js のマウスの軌跡をシンプルに使うプログラム、軌跡を描く部分の数を 4つにしてみた。ここからさらに、ちょっとした変更で楽しくできそうな予感。 pic.twitter.com/EfAEyD8bzO— you (@youtoy) January 1, 2022 とりあえず、動くには動いたのですが、ウィンドウの表示が意図しない感じになっていそうなので、もう少し詳細を見ていければと思います。 【追記】 この話に対して Twitter でもらったコメント このあたり、確かめたり対応したりできればと思います。 マウスの位置などのずれ Retinaの場合pixelDensityが効いてなくてマウス位置などがズレるのかもです— TAKAWO Shunsuke (@takawo) January 13, 2022 画面表示まわり Thank you for the comment!Before I do that, may I confirm that the rough procedure I have tried is correct?1. Download "https://t.co/MO1KIWqjMj"2. Download the files from GitHub except for the "p5test.js (It's a program I wrote)" in the attached image3. Execute the command pic.twitter.com/SGoqkgO5PP— you (@youtoy) January 13, 2022 上記の続きで、以下の回答をいただいた感じからすると、記事で書いていた手順は問題はなさそうです。 Looks about right. Can you try the p5js examples in examples/p5, like examples/p5/simulate-recursive-tree.js? Do those look OK or have the same problem?An earlier version had issues with retina displays; this is likely a pixel-ratio issue.Could you share p5test.js too?— Joao da Silva (@JoaoDaSilvaZ) January 13, 2022
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む