- 投稿日:2021-01-16T23:43:11+09:00
Zoom Web SDK を試す
この記事は、Zoom Web SDK を試してみた手順のメモです。
●Web - Client SDKs - Zoom Software Development Kit (Zoom SDK) - Zoom Developer - Technical Documentation and Reference
https://marketplace.zoom.us/docs/sdk/native-sdks/webZoom Web SDK の概要
公式ページの記載を引用して見てみます。
The Web SDK enables the development of video applications powered by Zoom’s core framework inside an HTML5 web client through a highly optimized WebAssembly module.
As an extension of the Zoom browser client, this SDK is intended for implementations where the end user has a low-bandwidth environment, is behind a network firewall, or has restrictions on their machine which would prevent them from installing the Zoom Desktop or Mobile Clients.引用元: 公式ドキュメントより
説明はいろいろと書いていますが、この SDK を使うと、ブラウザ上で Zoomクライアントを立ち上げることができるもののようです。
Zoom Web SDK をとりあえず試す
公式ドキュメントの「Quick install」を見ると、以下手順でサクッと試せるようです。
パッケージのインストール
まずは、任意のディレクトリでパッケージのインストールを行います。
この手順を試す時、最初は Node.js のバージョンを 12 にしていて途中の手順でエラーが出ました。その後、バージョンを 14 にして試してエラーが出なくなったので、補足しておきます。npm i @zoomus/websdk2つのキーの取得について
公式ドキュメントによると Web SDK を使う際に API Key と Secret を取得する必要があるようです。
Zoom のApp Marketplaceにアクセスしてログインをし、画面右上の「Develop」のメニューから「Build App」を選択します。
その後の手順については以下の記事などを参照して、JWT の「API Key」と「API Secret」の 2つを取得してください。以下は、Zoom API についての記事ですが、取得するキーは今回の Zoom SDK を用いる場合と同じでした。
●Zoom APIをPostmanで試す | ヤマムギ
https://www.yamamanx.com/zoom-api-postman/サンプルアプリのソースの取得
そして、公式ドキュメントの Sample Apps の部分に書かれた以下の手順を進めていきます。
まずは最初の2つのコマンドを実行して、ソースを取得し、取得したソースのサブフォルダへと移動します。
git clone https://github.com/zoom/sample-app-web.git --branch master --depth 1 cd sample-app-web/Localサンプルアプリのソースの書きかえ(キーの設定)
ここで、取得したソースの中の一部を書きかえます。具体的には、先ほど準備した 2つのキーを設定します。
取得したソースの「Local」フォルダ内のさらに下に「js」フォルダがあり、その中に「index.js」というファイルがあります。ソースの取得元の情報でいうと、以下の URL の「13行目」と「19行目」です。
●sample-app-web/index.js at master · zoom/sample-app-web
https://github.com/zoom/sample-app-web/blob/master/Local/js/index.js具体的には以下の部分で、
const API_KEY = "YOUR_API_KEY";
の部分とconst API_SECRET = "YOUR_API_SECRET";
の部分の式の右側に、先ほど取得しておいたキーを設定します。それが完了したら、以下のコマンドを順次実行していきます。
npm install npm run start
ブラウザでミーティング設定画面を開く
上記のコマンドを入力すると、以下のような文字などが出力されます。
ローカルでポート番号「9999」でアクセスできる状態になったようです。
「0.0.0.0」や「localhost」にポート番号 9999 を指定して、ブラウザでアクセスしてみてください。そうすると、以下の画面が表示されるので「Meeting Number」と「Meeting Password」のそれぞれに、参加したい Zoomミーティングの ID とパスワードを入力してください。
また、言語設定が「English」となっている部分は「Japanese 日本語」という選択肢があるので、プルダウンから選択して変更します。その後、画面のメニュー右端にある「Join」ボタンを押しましょう。
そうすると、以下のように自分が用意したブラウザ上のアプリから Zoom ミーティングに参加できます。この時、「Meeting Number」の数字の中に半角スペースが入るとうまくいかないようなので、ご注意ください。うまく接続できたら、別タブが開き、以下のように Zoomミーティングへ参加した際の画面が表示されます。
Zoomミーティングに入った後は、ブラウザ上の UI で画面共有の操作なども行うことができます。
おわりに
今回の内容は単にブラウザ上でZoomミーティング へ参加しただけで、これだけだと、Zoom 標準のブラウザからのミーティング参加機能と同じですが、ソースコードに手を入れれば拡張とかもできるかと思ってます。
詳細は確認できてないので、引き続き情報をチェックしてみようと思います。
- 投稿日:2021-01-16T23:43:11+09:00
Zoom Client SDK の Web SDK を試す
この記事は、Zoom Client SDK の Web SDK を試してみた手順のメモです。
●Introduction - Client SDKs
https://marketplace.zoom.us/docs/sdk/native-sdks/introduction
●Web - Client SDKs - Zoom Software Development Kit (Zoom SDK) - Zoom Developer - Technical Documentation and Reference
https://marketplace.zoom.us/docs/sdk/native-sdks/webZoom Client SDK の Web SDK の概要
公式ページの記載を引用して見てみます。
The Web SDK enables the development of video applications powered by Zoom’s core framework inside an HTML5 web client through a highly optimized WebAssembly module.
As an extension of the Zoom browser client, this SDK is intended for implementations where the end user has a low-bandwidth environment, is behind a network firewall, or has restrictions on their machine which would prevent them from installing the Zoom Desktop or Mobile Clients.引用元: 公式ドキュメントより
説明はいろいろと書いていますが、この SDK を使うと、ブラウザ上で Zoomクライアントを立ち上げることができるもののようです。
Web SDK をとりあえず試す
公式ドキュメントの「Quick install」を見ると、以下手順でサクッと試せるようです。
パッケージのインストール
まずは、任意のディレクトリでパッケージのインストールを行います。
この手順を試す時、最初は Node.js のバージョンを 12 にしていて途中の手順でエラーが出ました。その後、バージョンを 14 にして試してエラーが出なくなったので、補足しておきます。npm i @zoomus/websdk2つのキーの取得について
公式ドキュメントによると Web SDK を使う際に API Key と Secret を取得する必要があるようです。
Zoom のApp Marketplaceにアクセスしてログインをし、画面右上の「Develop」のメニューから「Build App」を選択します。
その後の手順については以下の記事などを参照して、JWT の「API Key」と「API Secret」の 2つを取得してください。以下は、Zoom API についての記事ですが、取得するキーは今回の Zoom SDK を用いる場合と同じでした。
●Zoom APIをPostmanで試す | ヤマムギ
https://www.yamamanx.com/zoom-api-postman/サンプルアプリのソースの取得
そして、公式ドキュメントの Sample Apps の部分に書かれた以下の手順を進めていきます。
まずは最初の2つのコマンドを実行して、ソースを取得し、取得したソースのサブフォルダへと移動します。
git clone https://github.com/zoom/sample-app-web.git --branch master --depth 1 cd sample-app-web/Localサンプルアプリのソースの書きかえ(キーの設定)
ここで、取得したソースの中の一部を書きかえます。具体的には、先ほど準備した 2つのキーを設定します。
取得したソースの「Local」フォルダ内のさらに下に「js」フォルダがあり、その中に「index.js」というファイルがあります。ソースの取得元の情報でいうと、以下の URL の「13行目」と「19行目」です。
●sample-app-web/index.js at master · zoom/sample-app-web
https://github.com/zoom/sample-app-web/blob/master/Local/js/index.js具体的には以下の部分で、
const API_KEY = "YOUR_API_KEY";
の部分とconst API_SECRET = "YOUR_API_SECRET";
の部分の式の右側に、先ほど取得しておいたキーを設定します。それが完了したら、以下のコマンドを順次実行していきます。
npm install npm run start
ブラウザでミーティング設定画面を開く
上記のコマンドを入力すると、以下のような文字などが出力されます。
ローカルでポート番号「9999」でアクセスできる状態になったようです。
「0.0.0.0」や「localhost」にポート番号 9999 を指定して、ブラウザでアクセスしてみてください。そうすると、以下の画面が表示されるので「Meeting Number」と「Meeting Password」のそれぞれに、参加したい Zoomミーティングの ID とパスワードを入力してください。
また、言語設定が「English」となっている部分は「Japanese 日本語」という選択肢があるので、プルダウンから選択して変更します。その後、画面のメニュー右端にある「Join」ボタンを押しましょう。
そうすると、以下のように自分が用意したブラウザ上のアプリから Zoom ミーティングに参加できます。この時、「Meeting Number」の数字の中に半角スペースが入るとうまくいかないようなので、ご注意ください。うまく接続できたら、別タブが開き、以下のように Zoomミーティングへ参加した際の画面が表示されます。
Zoomミーティングに入った後は、ブラウザ上の UI で画面共有の操作なども行うことができます。
おわりに
今回の内容は単にブラウザ上でZoomミーティング へ参加しただけで、これだけだと、Zoom 標準のブラウザからのミーティング参加機能と同じですが、ソースコードに手を入れれば何らか拡張とかもできるかと思ってます。
詳細は確認できてないので、引き続き情報をチェックしてみようと思います。また、今回使った「Client SDK」以外の SDK(例えば、「Fully Customizable SDK」)も見てみようと思います。
●Introduction - Client SDKs
https://marketplace.zoom.us/docs/sdk/native-sdks/introduction
●Introduction - Fully Customizable SDKs
https://marketplace.zoom.us/docs/sdk/custom/introduction
- 投稿日:2021-01-16T23:29:36+09:00
TensorFlow.js version of PoseNetで手旗信号読取りサイト
はじめに
初記事です。
以前Coral USB Acceleratorを購入したので、Raspberry Pi 4でPoseNetを動かして手旗信号を読み取るようなものを作って自己満足してました。
ボーイスカウトの指導者などをやっているので、スカウトたちにもやらせてみたいな、などと思ってたら、
Real-time Human Pose Estimation in the Browser with TensorFlow.js
ってのがあるんですね。すごい。というわけでタイトルの通り、読取りサイトを作ってみたので、その備忘録です。ベンチャー/ローバースカウトが興味を持ってくれるの期待して…
参考にしたもの
とはいえWebサイトやJavaScriptなどはほぼ触ったことないので各所を参考に。
PoseNet
何はともあれ姿勢推定してくれるPoseNetを、ということで、
Github - tensorflow/tfjs-models
で公開されているdemosからcamera.jsを丸パク…
実装の詳細説明は割愛しますが、poseDetectionFrame()内でPoseNetから17関節の座標を取得して骨人間とかを描画しているところに手旗信号の姿勢を判定するロジックを入れます。
ポーズを判定する
判定といってもどうすれば良いのか、ということでCoral Acceleratorで実装したときに参考にさせていただいた
から、肘と肩の内角を計算して、その角度の状態からポーズを判定します。
手旗信号
オールドスカウトなので手旗信号は一応マスターしているつもりですが、再確認&参考に下記サイト。
ボーイスカウト関連のかわいいイラストなどを提供してくれているサイトなのですが、手旗信号関連の参考イラストもたくさん。
基本的には数字の1~14までを表すポーズ(原画)があり、それを組み合わせてカタカナを表現するのが手旗信号です。
手旗信号の姿勢を判定する
さて本題の手旗信号認識です。
各関節の内角を計算する
まず1~14の数字を表す原画を判定するのですが、関節の角度を求めてその状態からどういうポーズをしているかを判定します。
ので3つの関節の座標から真ん中の関節の内角を求める関数。function calculateInternalAngle(keypoints, point0, point1, point2) { var a = {x:keypoints[point1].position.x-keypoints[point0].position.x, y:keypoints[point1].position.y-keypoints[point0].position.y}; var b = {x:keypoints[point2].position.x-keypoints[point0].position.x, y:keypoints[point2].position.y-keypoints[point0].position.y}; var dot = a.x * b.x + a.y * b.y; var absA = Math.sqrt(a.x*a.x + a.y*a.y); var absB = Math.sqrt(b.x*b.x + b.y*b.y); var cosTheta = dot/(absA*absB); var theta = Math.acos(cosTheta) * 180 / Math.PI; return theta; }手旗信号はほぼ腕の状態で判定するので、両肩と両肘の角度を求めておきます。
function getAngles(keypoints, minConfidence) { var angles = []; // left elbow deg = calculateInternalAngle(keypoints, LEFTELBOW, LEFTWRIST, LEFTSHOULDER, minConfidence); angles.push(deg); : // 省略 }内角なので腕を上げている場合の角度か、下げている場合の角度かを求めておきます。
function get_positions(keypoints, minConfidence) { positions = []; if((keypoints[LEFTELBOW].score > minConfidence) || (keypoints[LEFTWRIST].score > minConfidence)){ if((keypoints[LEFTELBOW].score > minConfidence) && (keypoints[LEFTELBOW].position.y < keypoints[LEFTSHOULDER].position.y) || (keypoints[LEFTWRIST].score > minConfidence) && (keypoints[LEFTWRIST].position.y < keypoints[LEFTSHOULDER].position.y)){ positions.push(UP); }else{ positions.push(DOWN); } : // 省略 }腕の状態から原画を判定
原画の一覧はポーラスターさんを参考に。
「2」は右上げと左上げの2種類、「11」は降り下げるジェスチャーなので上の状態と下の状態の2種類。
基本姿勢(原姿)を「0」として全17姿勢を判定。function judge_genkaku(keypoints, minConfidence){ angles = getAngles(keypoints, minConfidence); positions = get_positions(keypoints, minConfidence); if (150 < angles[ANG_LELBOW] && 150 < angles[ANG_RELBOW] && (80 < angles[ANG_LSHOULDER] && angles[ANG_LSHOULDER] < 130) && (80 < angles[ANG_RSHOULDER] && angles[ANG_RSHOULDER] < 130) && positions[LEFTHAND_UPDOWN] == DOWN && positions[RIGHTHAND_UPDOWN] == DOWN) return 0; : // 省略 }角度は微妙な調整が必要だったので、コテコテのコードですが?
判定した数値を配列にとっておきます。カナ(五十音)を判定
手旗信号は原画を続けて打って、基本姿勢(原姿)に戻るとカナ1つを打ち終えたと判断します。原画の形を組み合わせるとカタカナの形になります。
こちらもポーラスターさんの一覧を参考に。function judge_kana(text, genkakus) { strGen = genkakus.toString(); if (strGen == [9, 3]) return text + 'あ'; else if (strGen == [3, 2]) return text + 'い'; : // 省略 }という具合で原画の組み合わせをカナにします。
以上、手旗信号判定の簡単な流れでした。
最後に
ソースコードはこちらです。
Github読取りサイトはこちら
https://hiroshi32yoshida.github.io/posenet_flag_sign_js/うまく読み取るためのコツは注意点としてサイトに書いてありますが、
・背景がゴチャゴチャしていないこと
・服装と背景のコントラストがあること
・上半身の関節が隠れていないこと(手旗を持ってると判定できないことがあります)
などです。6とか9とか11が読取り渋いですが、条件良ければ上手く読み取ってくれます。
練習程度にはなると思います。ただ角度からの判定が微妙なことが多いので、ml5.jsの機械学習で原画をトレーニングして判定するVerも作成してみました。機械学習とかよくわかっていませんが。
次回記事で紹介します。以上です。
- 投稿日:2021-01-16T23:18:47+09:00
Luminousが上手く動かない件
ウェブサイトの復旧作業の中で、ギャラリーのページをカスタマイズする作業の中で、jQuery不要なLightboxスクリプトLuminousを知りました。
jQueryを使わないので、小規模のHTMLを手入力で作ったようなウェブサイトのギャラリーページのカスタマイズに最適だと思いました。
でも、下記のコードを設置しても、動かないです。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luminous-lightbox@2.3.2/dist/luminous-basic.min.css"> <script src="https://cdn.jsdelivr.net/npm/luminous-lightbox@2.3.2/dist/luminous.min.js"></script> <script> new LuminousGallery(document.querySelectorAll('.luminous')); </script>複数の画像に対応するため、このコードを使いました。
このコードは、こちらの記事で見つけました。
jQuery不要なLightbox代替スクリプトLuminousが本当に軽量こちらの記事を読んで、原因が分かりました。
Luminousを適用したいaタグの直下に、このコードを設置する必要があります。
理由は、他のCSSの影響を受けないように、最後にLuminousのCSSを適用させるためです。設置例
<div> <ul> <li><a class="luminous" href="./img/1_big.jpg"><img src="./img/1.jpg" alt="image" /></a></li> <li><a class="luminous" href="./img/2_big.jpg"><img src="./img/2.jpg" alt="image" /></a></li> </ul> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/luminous-lightbox@2.3.2/dist/luminous-basic.min.css" /> <script src="https://cdn.jsdelivr.net/npm/luminous-lightbox@2.3.2/dist/luminous.min.js"></script> <script>new LuminousGallery(document.querySelectorAll('.luminous'));</script> </div>
- 投稿日:2021-01-16T21:38:35+09:00
vuetifyで「[Vue warn]: The .native modifier for v-on is only valid on components but it was used on <div>.」
起きたこと
私の場合はカレンダー・コンポーネントを使った時に発生しました。
起動はしますが、ブラウザ上でwarningが出ます。
[Vue warn]: The .native modifier for v-on is only valid on components but it was used on <div>.
解決方法
その1 vuetifyのバージョンをあげる
このwarningについてはGitHubでissueがあがっていて、解決済です。(v-iconでも発生するようです)
[Bug Report] warning with VueJS 2.6.11 · Issue #9999 · vuetifyjs/vuetify
[Bug Report] Button wrapper missing for faSvg clickable v-icons · Issue #10623 · vuetifyjs/vuetify修正のPRは↓で、v2.3.14でリリース済です。
というわけで、v2.3.14に上げれば発生しなくなります。
その2 warningを無視するコードを入れる
様々な事情でバージョンをあげるのが難しい場合、無理やり無視する事も可能です。(warningなので動作に影響は無いようです)
該当のコードはこちら。
Nuxtの場合は、pluginとして書いてあげるとわかりやすいです。
ignore-warning.tsconst ignoreWarnMessage = 'The .native modifier for v-on is only valid on components but it was used on <div>.'; Vue.config.warnHandler = function (msg, vm, trace) { // `trace` is the component hierarchy trace if (msg === ignoreWarnMessage) { msg = null; vm = null; trace = null; }該当のwarningメッセージを握りつぶします。
- 投稿日:2021-01-16T20:57:29+09:00
[JavaScript] たのしいタグ付きテンプレート文字列
これはなに?
タグ付きテンプレート文字列で色々遊んでみる記事です。
タグ付きテンプレート文字列とは?
文字列と言っていますが、文字列と言うよりは、関数の呼び出しかたです。
例えば、ある関数があったとしまして
function myFunc(){}普通はこのように呼び出しますが、
myFunc();このように呼び出すことを、タグ付きテンプレート文字列と言います。
myFunc``ここで使用した関数を特別にタグ関数と言います。
タグ関数に渡される引数
タグ関数に渡される引数は、文字列をパースした結果になります。
第1引数は配列です。式以外の部分文字列が入っています。
第2引数以降は可変長です。式を評価した結果になります。実際にどのような引数が渡されるのか確認するために、このような関数を定義しました。
function myTag(strings, ...keys) { console.log('strings = ', strings); console.log('keys = ', keys); }呼び出してみます。
myTag`abc`; /* 結果 : strings = (1)["abc"] keys = (0)[] */myTag`Java${100}Script`; /* 結果 : strings = (2)["Java" ,"Script"] keys = (1)[100] */myTag`pl ${1 + 1} mu ${2 * 2} di ${3 / 3}`; /* 結果 : strings = (4)["pl " ," mu " ," di " ,""] keys = (3)[2 ,4 ,1] */組み込み関数をタグ関数として使ってみる
こんなこともできますが、意味はないですねww
parseInt`abc` // 結果 : NaN parseInt`010` // 結果 : 10 encodeURI`\n` // 結果 : '%0A'色々な値を返すタグ関数
タグ関数はただの関数なので、Promiseを返したり、関数を返したりもできますね。
意味なくPromise返してみたり。
function myTag(strings) { return new Promise((resolv) => { resolv(strings.join('|'); }) }myTag`a${0}${1}b`.then(console.log); // 結果 : 'a||b'関数を返してみたり。
function myTag(strings) { return function(d) { return strings.join(d); } }console.log(myTag`a${0}${1}b`('---')); // 結果 : 'a------b'おまけ : TypeScriptでタグ関数を定義する
引数を
TemplateStringsArray
にします。function myTag(strings: TemplateStringsArray, ...keys: Array<any>): any { // (snip) }
- 投稿日:2021-01-16T19:48:08+09:00
IEでconsole.logは使用できない。
- 投稿日:2021-01-16T18:56:41+09:00
JavaScriptの関数とオブジェクトにおける最低限の知識
本記事の目的
この記事は自身のJavaScriptに対する知識の定着を図るため、また、同じような初学者が理解するきっかけになればと思い作成しています。間違い等ございましたらお手数ですがご連絡いただけますと幸いです。
JavaScriptの概要とメリット
プログラミング言語の一つ。クライアントサイドに用いられる。
例えば某サイトで服を購入しようと考えた際に服→メンズ→サイズ...と選択する際にマウスのポインタを選択肢上に移動させると次々に新しい選択項目が表示されるようなものをイメージしてもらうとわかりやすいかと思う。
上記の例で話すのであれば、ページの移動なしで画面の表示を変更することができる、サーバーとの通信回数を減らすことができるというメリットがある。コンソールパネルを用いてJavaScriptを実行する
JavaScriptのコードを実行し、その結果を表示するためにはデベロッパーツールを使用する。一般的なブラウザに付属しており誰でも使用することができる。
ブラウザ上で右クリック→検証を押す、もしくはcommand + option + c
キーで表示可能。
また、デベロッパーツールは検証ツールと言われ、以下のような作業ができる。
- 表示しているサイトのHTMLの要素の確認・編集
- 表示しているサイトのCSSの確認・編集
- JavaScriptの実行
JavaScriptにおける変数について
var,const,letの三種類を用いて変数を定義する。
それぞれの違いは以下の通り。
var・・・再定義と再代入が可能。
const・・・再定義と再代入ともに不可能。
let・・・再代入は不可能だが、再定義は可能。varの使用(検証ツールのconsoleより)
'var' var sample = "Hello" console.log(sample) Hello(←が表示される) '再定義' var sample = "再定義" console.log(sample) 再定義(←が表示される) '再代入' sample = "再代入" console.log(sample) 再定義(←が表示される)constの使用(検証ツールのconsoleより)
'const' var sample = "Hello" console.log(sample) Hello(←が表示される) '再定義' var sample = "再定義" console.log(sample) エラーになる '再代入' sample = "再代入" console.log(sample) エラーになるletの使用(検証ツールのconsoleより)
'let' let sample = 'Hello' console.log(sample) Hello(←が表示される) '再定義' let sample = "再定義" console.log(sample) エラーになる ※2021年1月16日現時点で、Google chromeだとエラーにならない。バージョンアップにて変更した模様? 要注意です! '再代入' let sample = "再定義" console.log(sample) 再定義(←が表示される)オブジェクト
プロパティを複数集めたものの集合体のこと。また、プロパティとはキーとバリューによって構成されている。
オブジェクトの値を取得するためにはオブジェクト名.プロパティ名のように記述することで取得することができる。
'例' const sample = { color: 'blue'} console.log(sample.color) blue(←が表示される)
- 投稿日:2021-01-16T18:42:00+09:00
【初心者】#1 Reactの基礎とMaterial-UI使って綺麗に作ってみる
Reactでかっこいいページを作りたい!
- 国内ではVue.jsの人気も高いですが、Reactの方が海外では流行っている
React Server Components
なるものが出てきた- 下火気味?だけどReact Nativeをもしやる事になっても、少しは対応しやすくなるかも
ということで、
バックエンドが専門の私ですが、JavaScriptのスキルアップかねてReactをはじめました。デザインはMaterial UIに任せよう
デザイナーでもフロントエンジニアでもない私は、CSS Frameworkに頼ります!
情報量の多さから、Material UIを使うのが良いと判断して勉強開始。ReactもMaterial UIも英語読めないと対処しにくいところあるので、
誰かの助けになればいいなと思って作りながらメモしながら書いてます。トピック
対象:
- react初心者
- CSS苦手な人へ
- Reactやってみたいけど、デザインが…
- とりあえず見た目が及第点欲しい人の基礎の基礎
やること
- インストール、
react-create-app
から始める- ヘッダー作成
- グリッド(レスポンシブ)
- Reactでのアイコン付け方
- カード、ボタン、画像を使って見た目を整える
環境作る
前提:nodejs入れてない人はインストールしてください。nodejsと調べて、LTSという方をダウンロードしてインストール進めればOKなはずです。
Reactのファイル作りたいところに移動してから、以下でアプリ作ります。
名前はmaterial-react
で作ってみます。$ npx create-react-app material-react $ cd material-react/node_modulesサーバーを起動。
$ npm startreactのマークがくるくる回ってたらOK
Material-UI使えるようにする
公式サイトの通りにインストールしていく。
$ npm install @material-ui/core必須ではないけど、以下をやっていきます。
index.htmlにフォントを追記。titleタグ付近にでも。index.html<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />'Roboto'つかうと書いてあるので、フォントの優先度をあげます。
index.cssbody { margin: 0; font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }アイコンを使うので、インストール。
$ npm install @material-ui/iconsデフォルトのページいらないので変更
軽く説明すると、
- index.htmlの
<div id="root"></div>
この要素をJSでいじりまくってタグとか生成して作っていく感じ- App.jsがJSファイルの親玉?先祖?みたいな感じ
- componentsフォルダ作って、その中に部品となるもの作り、App.jsにコンポーネントを埋め込んで作っていくが一般的。例えば、サイドバー用のJS、ヘッダー用のJSとか。
では、デフォルトページを修正。
初期状態では、コンポーネントが存在しないで、App.jsに全てが書いてあります。
全部をApp.jsに作ることもできますが、
Reactは機能ごとにコンポーネントに分けて作るのが普通です。では、Reactマークのくるくるさせるための記述と、
デザインが、App.jsとApp.cssに書かれていますので、
Material-UI使うために、白紙のページにします。白紙ページにする
- App.css中身全部消す
- App.jsの項目削除して真っ白なページにする
App.jsimport logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> 真っ白 </div> ); } export default App;Reactマークが消えて、真っ白とだけ表示されてればOK
グリッド、レスポンシブ
Bootstrapと同じですね。
画面を横方向を12分割にしてその要素は、12個ののうち、何個分の横幅を使うの?
ってやつです。flexbox使うより簡単にレスポンシブ対応できるので、専門でない人には便利です!
https://material-ui.com/components/grid/#grid
※いまいちわからない方は↑ページ開いて、ブラウザのウィンドウを小さくしたり、大きくしたりしてみてください。material-react/src/App.jsimport './App.css'; import { Grid } from '@material-ui/core'; function App() { return ( <Grid container direction="column"> <Grid item> item1item1item1item1item1item1item1item1item1item1item1item1 </Grid> <Grid item container> <Grid sm={2} /> <Grid xs={12} sm={8}> item2item2item2item2item2item2item2item2item2item2item2item2 item2item2item2item2item2item2item2item2item2item2item2item2 item2item2item2item2item2item2item2item2item2item2item2item2 item2item2item2item2item2item2item2item2item2item2item2item2 item2item2item2item2item2item2item2item2item2item2item2item2 </Grid> <Grid sm={2} /> </Grid> </Grid> ); } export default App;
<Grid container>
という親の中に<Grid item>
という子を入れていきます。
<Grid item container>
分割された子の要素の中をさらに分割するため、container入れてます。
<Grid sm={2} />
これが二つありますが、これが左右の余白です。
xsが超小さい画面の時には余白なし。小さい画面以上の時は、 2/12の空白を入れてます。
2/12が二つなので、本体は残りの8/12。なので
<Grid xs={8}>
ブラウザの画面を手動で大きくしたり、小さくしたりして変化するか試してください。
ヘッダーを作る
srcのなかにコンポーネントフォルダを作ります。
その中にHeader.js
作成$ mkdir src/componentsmaterial-react/src/components/Header.jsimport React from 'react' function Header() { return ( <div> ヘッダー </div> ) } export default HeaderヘッダーコンポーネントをApp.jsに追加
作ったヘッダーコンポーネントを親玉のApp.jsの中につっこみます。
material-react/src/App.jsimport Header from './components/Header'; ・・・ <Grid container direction="column"> <Grid item> <Header /> </Grid> ...単純に「ヘッダー」という文字が出るだけですが、
ヘッダーコンポーネント(ヘッダーの部品)が読み込まれてます。これだとしょぼいので、公式サイトから使用例をパクって改造します。
https://material-ui.com/components/app-bar/
https://material-ui.com/ja/api/app-bar/基本的なものだけで構成してみました。
material-react/src/components/Header.jsimport { AppBar, Toolbar, Typography } from '@material-ui/core' import React from 'react' function Header() { return ( <AppBar position="static"> <Toolbar> <Typography>ヘッダー</Typography> </Toolbar> </AppBar> ) } export default Headerヘッダーなので
position="static"
にしてます。
これ指定しないと、ヘッダーに要素が重なってしまいます。
アイコンをつける
検索して良いアイコンを探す。
好きなアイコンをクリックすると下の画像みたいな表示が出る。今回はこのシルエットみたいなアイコンを試しに貼り付けてみます。
importのところをコピーしてHeader.jsに貼り付け。iconを使えるようにします。
Header.jsimport AccountCircleOutlinedIcon from '@material-ui/icons/AccountCircleOutlined'; <AppBar position="static"> <Toolbar> <Typography>ヘッダー</Typography> <AccountCircleOutlinedIcon /> </Toolbar> </AppBar>ただ、普通、こういうのって、左端にありますよね。
ということで、CSSをいじって、調整します。Material-UIでCSSを追加
makeStyleを使ってみましょう。
Material-UIで作るときにCSSを書くとき使うもののようです。
ファイル一つにたくさんのCSS書くより、コンポーネントに分かれてるし、そこにCSS書けばよくない?
ってことで使われるらしいです。(?)
当然、JSで書くので計算とか、条件とか、Scssっぽく?便利にデザインを適用もできますね。Header.jsimport React from "react"; import { AppBar, Toolbar, makeStyles, Typography } from "@material-ui/core"; import AcUnitRoundedIcon from "@material-ui/icons/AcUnitRounded"; const useStyles = makeStyles(() => ({ typographyStyles: { flex: 1 } })); const Header = () => { const classes = useStyles(); return ( <AppBar position="static"> <Toolbar> <Typography className={classes.typographyStyles}> Anthony sistilli </Typography> <AcUnitRoundedIcon /> </Toolbar> </AppBar> ); }; export default Header;
className
はHTMLのclassのことです。reactの中ではclassNameと書きます。で、クラスをmakeStyleで生成するということで↓追加。
const useStyles = makeStyles(() => ({ typographyStyles: { flex: 1 } }));useStyles作って
const classes = useStyles();
でclasses作って、
classNameにオブジェクトのキー名typographyStyles
を設定しているので
classes.typographyStyles
で、ここの要素にflex: 1
を適用するということです。コンテンツ部分のコンポーネントを作る
$ touch src/components/Content.js
Content.js
作成。App.js
に
ヘッダーの時と同じようにインポートと、<Content />
とを入れる。App.jsimport Content from './components/Content'; ... <Grid container direction="column"> <Grid item> <Header /> </Grid> <Grid item container> <Grid sm={2} /> <Grid xs={12} sm={8}> <Content /> </Grid> <Grid sm={2} /> </Grid> </Grid>コンテンツ部分は
「カード」
を使います。カードの部分もコンポーネントにしたいので
BodyCard.js
を作ります。$ touch src/components/BodyCard.jsContentコンポーネントの中にBodyCardコンポーネントが入れ子になってます。
App.jsからみるとBodyCardコンポーネントは孫に当たります。では、Outlined Cardというのを公式ページからパクってきて、
src/components/BodyCard.jsimport React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import Button from '@material-ui/core/Button'; import Typography from '@material-ui/core/Typography'; const useStyles = makeStyles({ bullet: { display: 'inline-block', margin: '0 2px', transform: 'scale(0.8)', }, title: { fontSize: 14, }, pos: { marginBottom: 12, }, }); function BodyCard() { const classes = useStyles(); const bull = <span className={classes.bullet}>•</span>; return ( <Card variant="outlined"> <CardContent> <Typography className={classes.title} color="textSecondary" gutterBottom> Word of the Day </Typography> <Typography variant="h5" component="h2"> be{bull}nev{bull}o{bull}lent </Typography> <Typography className={classes.pos} color="textSecondary"> adjective </Typography> <Typography variant="body2" component="p"> well meaning and kindly. <br /> {'"a benevolent smile"'} </Typography> </CardContent> <CardActions> <Button size="small">Learn More</Button> </CardActions> </Card> ); } export default BodyCardカードを一つだけ表示させてみます。
Content.jsimport React from 'react' import BodyCard from './BodyCard' function Content() { return ( <BodyCard /> ) } export default Content3個表示すると
Content.jsimport { Grid } from '@material-ui/core' import React from 'react' import BodyCard from './BodyCard' function Content() { return ( <Grid container> <Grid item xs={4}> <BodyCard /> </Grid> <Grid item xs={4}> <BodyCard /> </Grid> <Grid item xs={4}> <BodyCard /> </Grid> </Grid> ) } export default Contentスペースを入れて見た目調整
くっついていて見た目良くないので、調整します。
Material-UI公式ページのgridの項目で
spacingの項目で確認してからやるといいかもしれません。
spacing={2}
足す。もっと開けたいときは数字を大きくするといいです。Content.jsreturn ( <Grid container spacing={2}> <Grid item xs={4}> <BodyCard /> </Grid> <Grid item xs={4}> <BodyCard /> </Grid> <Grid item xs={4}> <BodyCard /> </Grid> </Grid> )あとは、好みで調整してみてください。
画面のサイズによってどのような横幅にするかをxs, sm md, lg, xl
で決められます。
Bootstrapと同じ感じ。今回は、スマホなど画面が非常に小さくなると、カードが一つずつ。smサイズで1行に3個並べるようにしました。
↓xsサイズにすると
カードの見た目改造 カードのヘッダー、クリックできるアイコン
カードの中のヘッダーとクリックできるアイコンを用意します。
今回は⭐️アイコンつけます。Card要素の一番初めにCardHeaderを追加して、
⭐️アイコンを調べてインポート(StarBorderOutlinedIcon)。
該当箇所に貼り付けます。BodyCard.jsimport CardHeader from '@material-ui/core/CardHeader'; import Avatar from '@material-ui/core/Avatar'; import IconButton from '@material-ui/core/IconButton'; import StarBorderOutlinedIcon from '@material-ui/icons/StarBorderOutlined'; <Card variant="outlined"> <CardHeader avatar={ <Avatar aria-label="recipe" className={classes.avatar}> R </Avatar> } action={ <IconButton aria-label="settings"> <StarBorderOutlinedIcon /> </IconButton> } title="Shrimp and Chorizo Paella" subheader="September 14, 2016" />IconButtonがあるとホバーした時に違い出て、押せる感じになってます。
アバターと画像は適当な画像をランダムで取得できるサービスあったのでテストで使います。
BodyCard.jsimport { CardMedia } from '@material-ui/core'; . . . function BodyCard(props) { const { avatarUrl, title, subheader, text, imageUrl } = props; const classes = useStyles(); const bull = <span className={classes.bullet}>•</span>; return ( <Card variant="outlined"> <CardHeader avatar={<Avatar src={avatarUrl} />} action={ <IconButton aria-label="settings"> <StarBorderOutlinedIcon /> </IconButton> } title={title} subheader={subheader} /> <CardMedia style={{ height: "150px" }} image={imageUrl} /> <CardContent> <Typography variant="body2" component="p"> {text} </Typography> </CardContent> <CardActions> <Button size="small">詳細をみる</Button> </CardActions> </Card> ); }Content.js. . . function Content() { return ( <Grid container spacing={2}> <Grid item xs={12} sm={4}> <BodyCard title="タイトル1" subheader="サブヘッダー1" avatarUrl="https://joeschmoe.io/api/v1/random" imageUrl="https://picsum.photos/150" text="カードの説明1" /> </Grid> <Grid item xs={12} sm={4}> <BodyCard /> </Grid> <Grid item xs={12} sm={4}> <BodyCard /> </Grid> <Grid item xs={12} sm={4}> <BodyCard /> </Grid> </Grid> ) }今は、propsを一個めのカードにしか与えてないので、このようになってます。
では、残りのカードにも表示されるようにして、
Content.jsimport { Grid } from '@material-ui/core' import React from 'react' import BodyCard from './BodyCard' const cardContents = [ { title: "タイトル1", subheader: "サブヘッダー1", avatarUrl: "https://joeschmoe.io/api/v1/random", imageUrl: "https://picsum.photos/150" }, { title: "タイトル2", subheader: "サブヘッダー2", avatarUrl: "https://joeschmoe.io/api/v1/random", imageUrl: "https://picsum.photos/150" }, { title: "タイトル3", subheader: "サブヘッダー3", avatarUrl: "https://joeschmoe.io/api/v1/random", imageUrl: "https://picsum.photos/150" }, { title: "タイトル4", subheader: "サブヘッダー4", avatarUrl: "https://joeschmoe.io/api/v1/random", imageUrl: "https://picsum.photos/150" }, ] function Content() { const getCardContent = getObj => { return ( <Grid item xs={12} sm={4}> <BodyCard {...getObj} /> </Grid> ); }; return ( <Grid container spacing={2}> {cardContents.map(contentObj => getCardContent(contentObj))} </Grid> ) } export default Content同じ画像になりますができました。
次回はデータをAPIで取得して表示する方法について触れます。
- 投稿日:2021-01-16T18:22:48+09:00
yarnを最新化する
はじめに
yarnを最新化する時に手間取ったので、備忘録としてメモを残す。
結論としては、yarnのアンインストール->インストールだけでは不十分で、local/bin/配下のyarn,yarnpkgを削除する必要がある。
開発環境
- macOS Big Sur(バージョン 11.1)
最新化する手順
/usr/local/bin配下のyarn,yarnpkgを削除する
/usr/local/lib/node_modules/yarn/bin配下のyarn,yarnpkgを最新化する
$ npm uninstall --global yarn $ npm install --global yarnあと書き
npm uninstallは/usr/local/lib/node_modules/yarn/bin配下のファイルを削除するのであって、/usr/local/binを更新してくれるわけではなさそう。
- 投稿日:2021-01-16T18:16:38+09:00
クレジットカードの公開鍵の書き方
- 投稿日:2021-01-16T17:06:08+09:00
繰り返し利用可能なドロワーをJavaScriptで書く
See the Pen 繰り返し利用可能なドロワーをJavaScriptだけで書く by 熊瀬川直也 (@momonoki1990) on CodePen.
使い方
- ドロワーの開閉ボタンに
data-drawer-btn="true"
data-drawer-target="{ドロワーのid}"
をセットする- ドロワー本体に
id
class="drawer"
data-drawer="true"
をセットする。- ドロワーを閉じるボタンに
class="drawer"
data-drawer-close-btn="true" data-drawer-target="{ドロワーのid}"
をセットするベタがき
drawer.html<div id="main"> <div class="my-drawer1"> <button class="drawer-btn" data-drawer-btn="true" data-drawer-target="drawer1"> 開閉ボタン1 </button> <div class="drawer" id="drawer1" data-drawer="true"> <div> <button class="drawer-close-btn" data-drawer-close-btn="true" data-drawer-target="drawer1">x</button> </div> <div class="drawer-menu"> <div class="drawer-title"> ドロワー1です </div> </div> </div> </div> <div class="my-drawer2"> <button class="drawer-btn" data-drawer-btn="true" data-drawer-target="drawer2"> 開閉ボタン2 </button> <div class="drawer" id="drawer2" data-drawer="true"> <div> <button class="drawer-close-btn" data-drawer-close-btn="true" data-drawer-target="drawer2">x</button> </div> <div class="drawer-menu"> <div class="drawer-title"> ドロワー2です </div> </div> </div> </div> <div class="my-drawer3"> <button class="drawer-btn" data-drawer-btn="true" data-drawer-target="drawer3"> 開閉ボタン3 </button> <div class="drawer" id="drawer3" data-drawer="true"> <div> <button class="drawer-close-btn" data-drawer-close-btn="true" data-drawer-target="drawer3">x</button> </div> <div class="drawer-menu"> <div class="drawer-title"> ドロワー3です </div> </div> </div> </div> </div> <style> .drawer { position: fixed; top: 0; right: 0; padding: 1rem; background-color: red; width: 300px; height: 100%; z-index: 100; transition: all 0.2s; transform: translate(340px); } .drawer-open { transform: translate(0px); } .drawer-close-btn { position: absolute; top: 0; left: 0; } .fade-layer { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; background-color: #000000; opacity: 0.5; z-index: 99; } .d-none { display: none; } </style> <script type="text/javascript"> // フェードレイヤーを生成しておく window.addEventListener('DOMContentLoaded', () => { const main = document.getElementById('main'); const fadeLayer = document.createElement('div'); fadeLayer.setAttribute('id', 'fade-layer'); fadeLayer.classList.add('fade-layer', 'd-none'); main.prepend(fadeLayer); }) // フェードレイヤーの表示・非表示切り替え toggleFadeLayer = () => { const fadeLayer = document.getElementById('fade-layer'); fadeLayer.classList.toggle('d-none'); } // ドロワーの表示・非表示切り替え const toggleDrawer = (event) => { const target = event.target; const drawerTarget = target.getAttribute('data-drawer-target'); const drawer = document.getElementById(drawerTarget); drawer.classList.toggle('drawer-open'); } // ドロワーの開閉ボタンにクリックイベントを仕込む const drawers = document.querySelectorAll('[data-drawer-btn="true"]'); drawers.forEach((drawer) => { drawer.addEventListener("click", (event) => { toggleDrawer(event); toggleFadeLayer() }) }) // ドロワーを閉じるボタンにクリックイベントを仕込む const drawerCloseBtns = document.querySelectorAll('[data-drawer-close-btn="true"]'); drawerCloseBtns.forEach(closeBtn => { closeBtn.addEventListener('click', (event) => { toggleDrawer(event); toggleFadeLayer(); }) }) // フェードレイヤーにクリックイベントを仕込む // フェードレイヤーがクリックされたらドロワーを閉じて、フェードレイヤーを非表示にする window.addEventListener('DOMContentLoaded', () => { const fadeLayer = document.getElementById('fade-layer'); fadeLayer.addEventListener('click', () => { const openingDrawer = document.getElementsByClassName('drawer-open')[0]; openingDrawer.classList.remove('drawer-open'); fadeLayer.classList.add('d-none'); }) }) </script>
- 投稿日:2021-01-16T16:48:40+09:00
JavaScriptのオブジェクト比較をできるだけ短いコードで行う
はじめに
Reactを書いていて、initialState(初期ステート)とstate(現在のステート)の比較を行いたいことがあった。
しかし、意外とJavaScriptではオブジェクトの比較が難しかったので、できるだけ短いヘルパー関数を作ったので共有したい。結論
helper.js/* オブジェクトをソート済み配列に変換する */ const objToSortedArray = obj => Object.entries(obj).sort() /* ソート済み配列を文字列に変換して比較する */ const isEqualOneDimentionalArray = (obj1, obj2) => JSON.stringify(objToSortedArray(obj1)) === JSON.stringify(objToSortedArray(obj2)) /* 再帰処理を行い、ネストされたオブジェクトまで比較する */ export const isEqual = (obj1, obj2) => isEqualOneDimentionalArray(obj1, obj2) && objToSortedArray(obj1).map(([key, val]) => typeof val === "object" ? isEqual(val, obj2[key]) : true)howToUse.jsimport {isEqual} from "./helper.js" const initialState = { tmpConditions: { target: "makeup", personalColor: false, faceType: false, items: [] } } const state = { tmpConditions: { target: "makeup", personalColor: true, faceType: false, items: [1, 23] } } console.log(isEqual(initialState, state)) // false
- 投稿日:2021-01-16T16:04:48+09:00
javascriptでif関数やswitch関数を作る(別記事のものを参考にしました)
最初に前提として書いておくと、javascriptでifやswitchは文となっています。この記事では、そんな二つの文法を返り値を返せるようにiff関数やswitchf関数として実装するというものです。
https://qiita.com/Yametaro/items/17f5a0434afa9b88c3b1
の感想で書いていたものになります。このページに掲載するプログラムは元記事の物を参考にしています。if関数改めiff関数
これに関しては、元記事の中でも元記事の感想欄でも指摘されてましたが、通常は三項演算子を使ってください。
元記事の感想欄で失敗したので、省略はできないとします。
感想欄でも書いたものになりますが、thenとelseの順番が逆でもいいバージョンを作ってみました。const iff = cond=>{ const met = cond2=>func=>{ const revmet = revfunc => { return cond2? func():revfunc(); } return (cond==cond2)?{else:revmet}:{then:revmet} }; return {then:met(cond),else:met(!cond)}; } //以下サンプル a=true; document.write(iff(a).then(()=>"that is right<br>").else(()=>"that is wrong<br>")); document.write(iff(a).else(()=>"that is wrong<br>").then(()=>"that is right<br>"));いい実装かはわかりませんが、仕組みを説明します。最後の
return {then:met(cond),else:met(!cond)};
というところを見てください。thenを先にした時とelseを先にした時で、引き渡している条件が逆転しています。これが肝となっています。cond(指定した条件式)とcond2を整理したいと思います。
thenが先かelseが先か cond cond2 then true true else true false then false false else false true まず、最後のcond2に注目してください。cond2がtrueになるときはthenが先で条件式がtrueの時と、elseが先で条件式がfalseの時です。つまり先に指定された方の関数の返り値を返すときです。次にcond2がfalseになるときはelseが先で条件式がtrueの時と、thenが先で条件式がtrueの時です。つまり後に指定した方の関数返り値を返すときです。つまり、条件式だったり、thenとelseどっちが先かによらず先に指定した関数か、後に指定した関数かどっちの関数の返り値を返せばいいのか一緒になっています。なので、revmet関数は単にcond2によって分岐しているだけになっています。また、thenが後に来てもelseが後に来ても同じrevmetでいいというわけです。
次に、condとcond2を比較すると、両方trueの時と、両方falseの時にthenを先に指定しています。なのでcond==cond2
という式で、thenを含むオブジェクトを返すかelseを含むオブジェクトを返すかを分岐しています。
よって上記の簡単な実装で適切な返り値となっています。なかなか説明が難しかったのでうまく説明できた自信ないですけどわかりましたか?
ちなみにelseifいりますか?といってもelse-thenの順番で書く人はelseifはどこに書くんでしょうか?switch関数改めswitchF関数
作ろうかと思ったんですけど、なかなかうまくいかないので完成したら投稿します。方針としては、最初はcase関数の引数を可変長にしようと思ったんですけど複数のcase関数で同じ値を書かれたときの処理をどうするのか問題になりそうだったので、ttatsfさんのcase関数(やめ太郎さんバージョンだとthen関数)に関数を指定しなかったときはその後初めて指定されたときに指定した関数を指定するという風にしようと考えています。
他には
他にはなんか式にしたら便利そうな文ってありましたっけ?あったら関数の実装に挑戦するので教えてください。
- 投稿日:2021-01-16T14:15:45+09:00
ドラッグ&ドロップされた画像や音声ファイルをインラインimgやaudioタグに変換するツールをつくってみた
HTMLに画像を埋め込みたい場合に、下記のように、URLではなく直接データをBase64エンコードして埋め込むことができます。
<img src="data:image/png;base64,iVBORw0KGgoAAAAN...">
今回は、このタグを簡単に作成できるツールを作ってみました。
インラインimgタグ生成ツール
MIME type
image/png
とimage/jpeg
1 だけ受け付けるようにしてます。あと、とりあえず1MB以下の制限をつけてます。
【追記】音声ファイル(audio/wav
とmp3ファイル(audio/mpeg
)のみ)も対応してみました。See the Pen ImageAndAudioFileBase64Encoder(Under Construction) by kob58im (@kob58im) on CodePen.
参考サイト
- HTML&JavaScript - Drag&Dropでファイルを読み取るまでの解説とサンプル(バイナリビューワ) - Qiita
- JavaScriptでバイナリを扱いたい - Qiita
- よくある MIME タイプ - HTTP | MDN
参考サイト(画像関連)
- 画像をBase64でHTMLファイルに直接埋め込む方法 - design Edge
- [JavaScript] 画像変換:<img>要素 ⇔ Base64(相互変換) - Qiita
- 画像をドラッグ&ドロップで登録してプレビュー表示 - Qiita
参考サイト(Audio関連)
- ※自動再生アリ※音量注意※ 【ワテのHTML講座】ウェブサイトで音声ファイルを再生する【Base64エンコードでも可能】
一度描画してから再エンコーディングする処理となっているので、画質が劣化する可能性があります。音声ファイルの処理のほうを真似れば改善できそうですが、今のところ対応予定はありません。(単純に面倒くさい・・・) ↩
- 投稿日:2021-01-16T14:15:45+09:00
ドラッグ&ドロップされた画像をインラインimgタグに変換するツールをつくってみた
HTMLに画像を埋め込みたい場合に、下記のように、URLではなく直接データをBase64エンコードして埋め込むことができます。
<img src="data:image/png;base64,iVBORw0KGgoAAAAN...">
今回は、このタグを簡単に作成できるツールを作ってみました。
インラインimgタグ生成ツール
MIME type
image/png
とimage/jpeg
だけ受け付けるようにしてます。あと、とりあえず1MB以下の制限をつけてます。See the Pen ImageFileToBase64(Under Construction) by kob58im (@kob58im) on CodePen.
参考サイト
- 投稿日:2021-01-16T11:44:03+09:00
初心者限定!!Vueで横幅(width)の変化を検知する方法
今回は、タイトルにも書いてる通りwindowの横幅の変化を検知したいと思います!!!
長ったらしい話はせずにもうコードを書いていきますね!
まず、初めにdataオブジェクトで
currentWidth
というプロパティを宣言し、横幅が変化するたびに呼び出す関数を設定していきます。App.vue<script> export default { data() { return { currentWidth: window.innerWidth, } }, methods: { calculateWindowWidth() { // 横幅を取得する関数 this.windowWidth = window.innerWidth } } } </script>初期値として、
window.innerWidth
を設定しておきます。次に、DOM要素と紐づけられた後に行う関数
mounted
、DOM要素が消去される前の関数beforeDestroy
を用いて、横幅の変更を検知します。App.vue<script> export default { data() { return { currentWidth: window.innerWidth, } }, mounted() { // 横幅の変更を検知 window.addEventListener('resize', this.calculateWindowWidth) }, beforeDestroy() { // 横幅の変更を検知 window.addEventListener('resize', this.calculateWindowWidth) }, methods: { calculateWindowWidth() { // 横幅を取得する関数 this.currentWidth = window.innerWidth } } } </script>いかがだったでしょうか?
僕は、最初に
computed
で行ってしまい横幅の変更を検知してくれませんでした。最初は
computed
便利だな~って思ってたんですけど、最近使い方が難しいことに気づきました。なんとなく出来たので良しとします。
以上、「初心者限定!!Vueで横幅(width)の変化を検知する方法」でした!
良かったら、LGTM、コメントお願いします。
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
Thank you for reading
- 投稿日:2021-01-16T08:06:58+09:00
ぷい!Zdogで3Dモルカーを実装する
はじめに
モルカーがかわいくてブラウザ上でつついて遊びたいなと思い、てきとうに検索してたらZdogという3Dエンジンを見つけたので使ってみました。
モルカーとは
百聞は一見に如かず!
1話約3分なので見ましょう!
モルカー1話:バンダイチャンネル
モルカー2話:YouTube作ったもの
ブラウザ上で動かせる3Dモルカー
デモ実装
今回はhtmlファイル一つだけでささっとつくりました
入門的なのはこちらの記事が良かったです
かわいい3Dエンジン「Zdog」の紹介html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Zdog Tutorial</title> <script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script> </head> <body> <canvas width="500" height="500" class="zdog-canvas"></canvas> <script> //ここに3Dの実装をしていく </script> </body> </html>
<script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
インストールするのめんどくさかったのでCDN使ってますJavaScript
全部は長いのでGitHub見てください
<script> const mainColor = "#f2ebd1" const pink = "pink" const brown = "#705444" const illo = new Zdog.Illustration({ element: '.zdog-canvas', dragRotate: true }) (省略) let anchor = new Zdog.Anchor({ addTo: illo, }); let body = new Zdog.Shape({ addTo: anchor, stroke: 200, color: mainColor, path: [{ x: 0, y: 0 } , { arc: [ { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: -90 }, ] },], })
- まず
const illo = new Zdog.Illustration({})
で親インスタンスを生成します- 次に親となるオブジェクトを決めます。今回は
anchor
をトップにしてその下にbody
があります。以降body
に対してその他のオブジェクトを紐づけていきます- Shapeはそのままだと球体ですが、pathを使うと直線や曲線を作ることができます。
arc
arcは楕円曲線をつくれます
new Zdog.Shape({ addTo: illo, path: [ { x: -60, y: -60 }, // start { arc: [ { x: 20, y: -60 }, // corner { x: 20, y: 20 }, // end point ]}, { arc: [ // start next arc from last end point { x: 20, y: 60 }, // corner { x: 60, y: 60 }, // end point ]}, ], closed: false, stroke: 20, color: '#636' });赤の点(-60,-60)が始点となり、arcで指定されてる座標(20,-60),(20,20)/(20,60),(60,60)で作られる四角形の中に納まるよう曲線が描画されます。
yは下が+上が-です。
ここではモルカーの体の描画に使いたかったので、直線になるように指定してます。
他には、マズルを作るところでも使用してます。
let rightNose = new Zdog.Shape({ addTo: body, path: [ { x: 10, y: 70, z: 65 }, { bezier: [ { x: 15, y: 60, z: 65 }, { x: 10, y: 75, z: 60 }, { x: 0, y: 75, z: 60 }, { x: 0, y: 85, z: 55 }, ] }, { x: 0, y: 85, z: 55 }, ], closed: false, stroke: 5, color: brown });
- 鼻… ωのところのコードです
- ここではベジェ曲線を使用してます ※z軸は省略
座標いまいちですが…
始点(10,70)と終点(0,85)をωのガイドラインとして(0,75)から終点までを鼻の下、始点から(0,75)までが鼻になるようにしてます。
左右あわせてωになるようにしてます。参考
最後に
3Dのものを作るのは初めてでしたが、わりと直感的に書けるので実装しやすかったです。
細かい描画の実装は難しいのでポテトちゃんとかは作れなさそうです…
- 投稿日:2021-01-16T03:32:48+09:00
ニコニコ動画のページからタイトルetc.を取り出す
chrome拡張機能を作るときに必要になったので。
タイトル
titlevar row_data = document.getElementById('js-initial-watch-data').getAttribute("data-api-data"); var title = JSON.parse(row_data).video.title;タグをリストで
tagsvar row_data = document.getElementById('js-initial-watch-data').getAttribute("data-api-data"); var tags = JSON.parse(row_data).tags; for(var i=0; i<tags.length; i++){ console.log(tags[i].name); }あとがき
ニコニコ動画はjs-initial-watch-dataというIDの要素のdata-api-data属性にjson形式で様々なデータがくっついています。
このデータには今回取り出したような動画タイトルやタグのほか、コメントも含まれています。質問、誤りなどあったらコメントください。
- 投稿日:2021-01-16T01:42:37+09:00
【JavaScript】クリックしたときにポップアップを表示する
イメージ図
HTML
<button id="click-btn">クリック!</button> <div id="popup-wrapper"> <div id="popup-inside"> <div id="close">x</div> <div id="message"> <h2>あの人気のマンガが...</h2> <p>今なら80%オフ!</p> <a href="#">ゲットする</a> </div> </div> </div>CSS
#click-btn { display: block; margin: 20px auto; background-color: purple; color: white; border: 0; padding: 6px 10px; } #popup-wrapper { background-color: rgba(0, 0, 0, .5); position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: none; } #popup-inside { text-align: center; width: 100%; max-width: 300px; background: white; margin: 10% auto; padding: 20px; position: relative; } #message a { background: purple; color: white; text-decoration: none; padding: 6px 10px; } #close { position: absolute; top: 0; right: 5px; cursor: pointer; }JavaScript
const clickBtn = document.getElementById('click-btn'); const popupWrapper = document.getElementById('popup-wrapper'); const close = document.getElementById('close'); // ボタンをクリックしたときにポップアップを表示させる clickBtn.addEventListener('click', () => { popupWrapper.style.display = "block"; }); // ポップアップの外側又は「x」のマークをクリックしたときポップアップを閉じる popupWrapper.addEventListener('click', e => { if (e.target.id === popupWrapper.id || e.target.id === close.id) { popupWrapper.style.display = 'none'; } });