20210503のJavaScriptに関する記事は30件です。

そのURL、普通に貼るだけで本当にOK?

あらすじ URLの貼り方もっといい方法があるよ。という話です。 リンクを貼っただけで満足していますか? Qiitaなどで記事を書く時、SNSで紹介投稿をするとき、URLリンクを貼ることはよくあります。「このサイトでこう言っていて」とか「ここに書いてあるので見てください」とか。書いている方は、親切心のカタマリで、「きっと読む人の役に立つ」と思っているはずです。 しかし、自分がURLリンクが含まれたメールを受け取った時に、気が付きます。 それは、「URLを渡すから、あとは自分で探してね」というメッセージでもある。そんな解釈ができてしまうのです。どうしてそうなってしまうのでしょう? URLを渡されるだけでは不満? 正直、私も「URLが渡されれば、検索の手間も減るしいいよね。」くらいの感覚でしかいませんでした。ところが、「URLたくさん貼ってくれるのはいいけど、全部読むの大変なんだよね」という言葉をもらうことがありました。 その時の私は、「参考って書いてあるし!基本はURL飛ばなくても理解できるように書いてるんだよ」と、傲慢とも言える精神状態でした。そして、その拒否反応とも言える精神状態のせいで、大切なことに気が付けていませんでした。 そもそもなぜURLを貼るのか? なぜURLを貼るのか?その先に見て欲しい情報があるからです。例えば、Web広告であれば、その先に買って欲しい商品やサービスがあったりします。そのために、何を優先的に魅せるのかを計算して配置したり配色したりしています。これらはConversion Rate を上げるために、Web広告業界では当たり前の話です。 せっかく配置したURLリンクも、使えなければスペースの無駄。消した方がマシなのです。飛んだ先が長文だったとして、読者に対し、関係ない部分も全て読めと言っているようなものなのです。もちろん飛んだ先が、よくデザインされた、情報を探しやすいページであるのなら、この限りではないでしょう。User eXperienceが低い投稿というのは相手の時間を奪うことになりかねません。 しかしサボリーマンとしては、URLを貼るだけに留めたいものです。 この問題を解決する方法はあるのでしょうか? Web系エンジニアなら知っているでしょ? Qiitaなら、H2タグのタイトルなどに、リンクボタンが追加されているのはご存知ですよね?もちろんこの程度なら、エンジニアであるかに関わらず、多くの人が分かっているでしょう。サイト内の一部だけを読ませるためのリンクを貼り易いですよね。 しかし、せっかくWebエンジニアであるのならば、idの属性情報でリンクを貼れるということを活かしましょう。こんな感じに。 https://policies.google.com/terms?hl=ja&fg=1#toc-about 見て欲しい部分を範囲指定できる? 「idが全てのWebサイトで適切に配置されているとは限らない」 「ランダムな文字列がidに配置されたサイトもある」 と言った声が聞こえてきそうです。それでしたら、対処方法があります。 飛んだ先でハイライトしたい部分をURLに埋め込んでしまいましょう! 例えば、こちらのGooleのマニフェストが掲げられたサイトを見てみましょう。 https://about.google これが通常の方法でURLを貼り、アクセスした様子です。 次に、このリンクをご覧ください。 https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える これが特殊な方法でURLを貼り、アクセスした様子です。#text=という特殊な記法を用いて、URLに加工を施したものを利用しています。 しかし、こういったURL、普通にインターネットを閲覧していて見かけることは少ないです。なぜなら、Chromeではversion81以降に搭載された機能であり、まだ普及している途中であるためです。 https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える こちらのURLを書く時、Qiitaで書く際には2通りの方法を使うことができます。 1つはこちら。日本語などの2バイト文字が変換されています。 [https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える] (https://about.google/#:~:text=%E4%BD%BF%E5%91%BD&text=%E6%83%85%E5%A0%B1&text=%E6%95%B4%E7%90%86&text=%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9&text=%E4%BD%BF%E3%81%88%E3%82%8B) もう一つはこちら。日本語がそのままです。 [https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える] (https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える) 普通に文章を見せたいだけなら、上記の方法で大丈夫なはずです。しかし、Qiitaの読者ターゲットはプログラマーです。ならばこのような特殊文字にも対処せねばなりませんね。また、プログラマーでなくとも、スペースを埋め込みたかったりすると厄介です。 AZa-z09;,/?:@&=+$-_.!~*'()# これをURLとして使えるように変換したものがこちら。 AZa-z09%3B%2C%2F%3F%3A%40%26%3D%2B%24-_.%21%7E%2A%27%28%29%23 とても人間が扱えるような代物ではありません。でも大丈夫です。これを便利にするChromeアドオンが開発されたりしています。ご興味のある方は検索してみてください。 https://www.google.com/search?q=Chrome Addon ハイライト URL 検索してください? さらっと、Google検索結果のURLリンクを掲載しました。これも前述の「テキストをハイライトする」と同じように、検索条件を予め指定させたリンクを作ることができます。「検索してください。」というのではなく、検索結果は「こちらです。この中から選んでください。」という方が、親切だったりします。 [https://www.google.com/search?q=Chrome Addon ハイライト URL] (https://www.google.com/search?q=Chrome+Addon+%E3%83%8F%E3%82%A4%E3%83%A9%E3%82%A4%E3%83%88+URL) こちらも、例によって、特殊文字のエンコードが必要なものですね。 エンジニアですよね? 前述した方法のURLリンクを作るのって、意外と難しいです。Javascriptがある程度分かれば、簡単に変換できます。Chromeのデベロッパーツール内でコンソールを開き、インタプリタとしてJavascriptのencodeURI()とかを使えばなんとかなります。 しかし、世は大NoCode時代に突入しようとしています。サボリーマンである私は、便利なツールを使います。気が向いたら、アドオンを使おうかなと思っています。 まとめ 自分のための時短が、相手にも同じような時短になっていない場合がある。本当にその時短が、ボトルネックを解消させる時短なのか?自己満の時短になっていないか?サボりって奥が深いのですね。 Excelsior!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

そのURL、普通に貼るだけで本当に時短?

あらすじ URLの貼り方もっといい方法があるよ。という話です。 リンクを貼っただけで満足していますか? Qiitaなどで記事を書く時、SNSで紹介投稿をするとき、URLリンクを貼ることはよくあります。「このサイトでこう言っていて」とか「ここに書いてあるので見てください」とか。書いている方は、親切心のカタマリで、「きっと読む人の役に立つ」と思っているはずです。 しかし、自分がURLリンクが含まれたメールを受け取った時に、気が付きます。 それは、「URLを渡すから、あとは自分で探してね」というメッセージでもある。そんな解釈ができてしまうのです。どうしてそうなってしまうのでしょう? URLを渡されるだけでは不満? 正直、私も「URLが渡されれば、検索の手間も減るしいいよね。」くらいの感覚でしかいませんでした。ところが、「URLたくさん貼ってくれるのはいいけど、全部読むの大変なんだよね」という言葉をもらうことがありました。 その時の私は、「参考って書いてあるし!基本はURL飛ばなくても理解できるように書いてるんだよ」と、傲慢とも言える精神状態でした。そして、その拒否反応とも言える精神状態のせいで、大切なことに気が付けていませんでした。 そもそもなぜURLを貼るのか? なぜURLを貼るのか?その先に見て欲しい情報があるからです。例えば、Web広告であれば、その先に買って欲しい商品やサービスがあったりします。そのために、何を優先的に魅せるのかを計算して配置したり配色したりしています。これらはConversion Rate を上げるために、Web広告業界では当たり前の話です。 せっかく配置したURLリンクも、使えなければスペースの無駄。消した方がマシなのです。飛んだ先が長文だったとして、読者に対し、関係ない部分も全て読めと言っているようなものなのです。もちろん飛んだ先が、よくデザインされた、情報を探しやすいページであるのなら、この限りではないでしょう。User eXperienceが低い投稿というのは相手の時間を奪うことになりかねません。 しかしサボリーマンとしては、URLを貼るだけに留めたいものです。 この問題を解決する方法はあるのでしょうか? Web系エンジニアなら知っているでしょ? Qiitaなら、H2タグのタイトルなどに、リンクボタンが追加されているのはご存知ですよね?もちろんこの程度なら、エンジニアであるかに関わらず、多くの人が分かっているでしょう。サイト内の一部だけを読ませるためのリンクを貼り易いですよね。 しかし、せっかくWebエンジニアであるのならば、idの属性情報でリンクを貼れるということを活かしましょう。こんな感じに。 https://policies.google.com/terms?hl=ja&fg=1#toc-about 見て欲しい部分を範囲指定できる? 「idが全てのWebサイトで適切に配置されているとは限らない」 「ランダムな文字列がidに配置されたサイトもある」 と言った声が聞こえてきそうです。それでしたら、対処方法があります。 飛んだ先でハイライトしたい部分をURLに埋め込んでしまいましょう! 例えば、こちらのGooleのマニフェストが掲げられたサイトを見てみましょう。 https://about.google これが通常の方法でURLを貼り、アクセスした様子です。 次に、このリンクをご覧ください。 https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える これが特殊な方法でURLを貼り、アクセスした様子です。#text=という特殊な記法を用いて、URLに加工を施したものを利用しています。 しかし、こういったURL、普通にインターネットを閲覧していて見かけることは少ないです。なぜなら、Chromeではversion81以降に搭載された機能であり、まだ普及している途中であるためです。 https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える こちらのURLを書く時、Qiitaで書く際には2通りの方法を使うことができます。 1つはこちら。日本語などの2バイト文字が変換されています。 [https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える] (https://about.google/#:~:text=%E4%BD%BF%E5%91%BD&text=%E6%83%85%E5%A0%B1&text=%E6%95%B4%E7%90%86&text=%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9&text=%E4%BD%BF%E3%81%88%E3%82%8B) もう一つはこちら。日本語がそのままです。 [https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える] (https://about.google/#:~:text=使命&text=情報&text=整理&text=アクセス&text=使える) 普通に文章を見せたいだけなら、上記の方法で大丈夫なはずです。しかし、Qiitaの読者ターゲットはプログラマーです。このような特殊文字にも対処せねばなりません。また、プログラマーでなくとも、スペースを埋め込みたかったりすると厄介です。 AZa-z09;,/?:@&=+$-_.!~*'()# これをURLとして使えるように変換したものがこちら。 AZa-z09%3B%2C%2F%3F%3A%40%26%3D%2B%24-_.%21%7E%2A%27%28%29%23 とても人間が扱えるような代物ではありません。でも大丈夫です。これを便利にするChromeアドオンが開発されたりしています。ご興味のある方は検索してみてください。 https://www.google.com/search?q=Chrome Addon ハイライト URL 検索してください? さらっと、Google検索結果のURLリンクを掲載しました。これも前述の「テキストをハイライトする」と同じように、検索条件を予め指定させたリンクを作ることができます。「検索してください。」というのではなく、検索結果は「こちらです。この中から選んでください。」という方が、親切だったりします。 [https://www.google.com/search?q=Chrome Addon ハイライト URL] (https://www.google.com/search?q=Chrome+Addon+%E3%83%8F%E3%82%A4%E3%83%A9%E3%82%A4%E3%83%88+URL) こちらも、例によって、特殊文字のエンコードが必要なものですね。 エンジニアですよね? 前述した方法のURLリンクを作るのって、意外と難しいです。Javascriptがある程度分かれば、簡単に変換できます。Chromeのデベロッパーツール内でコンソールを開き、インタプリタとしてJavascriptのencodeURI()とかを使えばなんとかなります。 しかし、世は大NoCode時代に突入しようとしています。サボリーマンである私は、便利なツールを使います。気が向いたら、アドオンを使おうかなと思っています。 まとめ 自分のための時短が、相手にも同じような時短になっていない場合がある。本当にその時短が、ボトルネックを解消させる時短なのか?自己満の時短になっていないか?サボりって奥が深いのですね。 Excelsior!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ガウス過程をJavaScriptで実装して描画までしてみる

要は ガウス過程を下記とかで勉強したので、そのついでにJavaScriptで実装を試みました. 誤りがあるかもしれませんので、ご指摘いただければ助かります. (参考)下記のYoutube/Webサイト/PDF資料を参考にしています. Youtube 【数分解説】ガウス過程(による回帰) : データのばらつきやノイズを考慮した非線形もいける回帰がしたい Gaussian Process ThothChildren ガウス過程 統計数理学研究所 ガウス過程の基礎と教師なし学習 ガウス過程概要 ガウス過程でできること 詳しい説明は参考記事を確認ください. 簡単にいえば、ガウス過程はすでにデータが取れている複数の点と推定したい位置を使ってその点の値の範囲を分散含めて推定することができる手法と捉えています. 例えば、$y=3x$のような関係があるときに、ノイズもあったため、 $$(x,y) = (-1,-3.5), (2,6), (3, 10), (5,14)$$ なデータが取れたとします. このとき、xが3.5や2.5、1のときにどんな値になるかを推定します. そのとき2.5は参考になりそうなデータとしてx=2がy=6でx=3がy=10にあるため、大体$y=3x$ぐらいな関係になっていそうです. しかし、1では、前後が-1や2で少し間があいているため、$y=3x$になっているかやや心許ないです. その場合は、分散が大きめになっていたら良さそうです. つまり、 2.5のときは、7.5±0.5ぐらい 1のときは、3±1ぐらい でしょうという感じです ガウス過程の実際の計算 実際の計算は下記のものを使用しています.データとして与えられる値を$(x_1,y_1)\dots (x_n,y_n)$として, あらかじめカーネル関数$kernel(a,b)$も決めておきます. K = \left( \begin{array}{cccc} kernel(x_1, x_1) & kernel(x_1, x_2) & \ldots & kernel(x_1, x_n) \\ kernel(x_2, x_1) & kernel(x_2, x_2) & \ldots & kernel(x_2, x_n) \\ \vdots & \vdots & \ddots & \vdots \\ kernel(x_n, x_1) & kernel(x_n, x_2) & \ldots & kernel(x_n, x_n) \end{array} \right) と新しい点$x_{new}$との計算. \boldsymbol{k} = \begin{pmatrix} kernel(x_1, x_{new})\\ kernel(x_2, x_{new})\\ \vdots\\ kernel(x_n, x_{new}) \end{pmatrix} が用意できたら、 $$\mu = \boldsymbol{k}^T K^{-1} \boldsymbol{y}$$ によって平均が $$\sigma = k - \boldsymbol{k}^TK^{-1}\boldsymbol{k}$$ によって分散が求まります. これを細かく各xの座標で計算します. やってみた $y=sin(x)$のもとで分布を作ってみました. こんな感じになりました. 使ったライブラリ mathjs 行列計算(逆行列や行列の積)のため canvasjs グラフ表示のため 全部で100点ほど計算して分布を書いていますが、データ点は、5~15ずつランダムに飛ばしながらデータをガウス分布で散らせて決めています. コード canvaJSのサンプルから手を入れて変えていっているので、やや汚いのは、ご了承ください. $$y=3sin(x)$$ が実際の関数としています. これにノイズを加えたデータを取得します. ガウス過程の計算部分 function addGaussResults(realdatas) { let realdatasY = realdatas.map(({y})=>y); //Calc Kernel Matrix K | カーネルKを求めます let K = realdatas.map((data) => realdatas.map((data2) => kernel(data.x, data2.x) + NOISE_SIZE * (data.x == data2.x) ) ); //Calc k values with new_x and Xs | ベクトル kを求めます let ks = datas.map((data) => realdatas.map((realdata) => kernel(data.x, realdata.x) ) ); //calc mean | 平均μを求めます. 先ほどのμを求める式より let means = datas.map( function(data, index){ return { x:data.x , y:math.multiply(math.multiply(ks[index], math.inv(K)), realdatasY) }; }); //calc sigma | 分散σを求めます.先ほどのσを求める式より let sigmas = datas.map( function(data, index){ return kernel(data.x, data.x) - math.multiply(math.multiply(ks[index], math.inv(K)), ks[index]) }); } さきほどの式をそれぞれ実装下までなので、特別変わったことはありません. この式を計算するために逆行列の計算が必要で、mathjsを導入しました. 計算自体はそこまで難しくありません. 最もポピュラーなRBFカーネルに揃えたものです. コード全体 <!DOCTYPE HTML> <html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/9.3.2/math.min.js" integrity="sha512-vI5FJgd8TB/jorqozFDviYmt4s4j3rLDrGvGnvUh+SXql7YF+MjndWDLd/3q1Ez6Pu8exLyi2AFYerrOHqey0A==" crossorigin="anonymous"></script> <script> const DATA_NUM = 100; const X_VALUE_STEP = 0.08; const NOISE_SIZE = 0.5; //正規分布でノイズを決める関数 function rnorm(){ return Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random()); } //ランダムなx座標のサンプルをするためだけの関数 function indexDecide(){ const MIN_STEP = 5; const MAX_STEP_INTERVAL = 10; return MIN_STEP + Math.floor(Math.random() * MAX_STEP_INTERVAL); } //カーネル関数はRBFカーネルとして、パラメータは調整して決めました. function kernel(x1, x2){ let theta0 = 5; let theta1 = 5; let theta2 = 0; return theta0 * (Math.exp(-theta1 * (x1-x2)**2 /2)) + theta2; } function drawLine(chart, linepoints){ chart.options.data.push( { type: "line", name: "gauss mean", showInLegend: true, markerType: "triangle", markerSize: 0, dataPoints: linepoints } ); } function drawArea(chart, ranges){ chart.options.data.push( { type: "rangeSplineArea", markerSize: 0, name: "gauss range", dataPoints: ranges } ); } window.onload = function () { let datas = []; let averages = []; //正解の(x,y)列を求めておきます. for(let i = 0; i < DATA_NUM; i++){ let xPos = i * X_VALUE_STEP; let yPos = 3 * Math.sin(xPos); let sigma = NOISE_SIZE; datas.push({x:xPos, y:[yPos-sigma, yPos+sigma]}); averages.push({x:xPos, y:yPos}); } var chart = new CanvasJS.Chart("chartContainer", { theme: "light2", title: { text: "Gauss Process Sim" }, axisY: { title: "y value", }, toolTip: { shared: true }, legend: { dockInsidePlotArea: true, cursor: "pointer", }, data: [ { type: "rangeSplineArea", markerSize: 0, name: "Sigma Range", dataPoints: datas }, { type: "line", name: "Average", showInLegend: true, markerType: "triangle", markerSize: 0, dataPoints: averages }] }); chart.render(); let realdatas = []; let prevIndex = 0; let nextIndex = indexDecide(); function addScatters() { //データ点を決めて、realdatasに入れていきます. //次の点は、indexDecideランダムに決めた先の値になるようにします. for(var i = 0; i < chart.options.data[0].dataPoints.length; i++) { if(i <= nextIndex){ continue; } nextIndex = indexDecide() + nextIndex; realdatas.push({ x: chart.options.data[0].dataPoints[i].x, y: (chart.options.data[0].dataPoints[i].y[0] + chart.options.data[0].dataPoints[i].y[1]) / 2 + rnorm() * NOISE_SIZE }); } chart.options.data.push({ type: "scatter", name: "realdatas", markerType: "triangle", markerSize: 10, dataPoints: realdatas }); chart.render(); } addScatters(); addGaussResults(realdatas); function addGaussResults(realdatas) { let realdatasY = realdatas.map(({y})=>y); //Calc Kernel Matrix K let K = realdatas.map((data) => realdatas.map((data2) => kernel(data.x, data2.x) + NOISE_SIZE * (data.x == data2.x) ) ); //Calc k values with new_x and Xs let ks = datas.map((data) => realdatas.map((realdata) => kernel(data.x, realdata.x) ) ); //calc mean let means = datas.map( function(data, index){ return { x:data.x , y:math.multiply(math.multiply(ks[index], math.inv(K)), realdatasY) }; }); //calc sigma and ranges let sigmas = datas.map( function(data, index){ return kernel(data.x, data.x) - math.multiply(math.multiply(ks[index], math.inv(K)), ks[index]) }); let ranges = datas.map( function(data, index){ return { x:data.x, y:[means[index].y - sigmas[index], means[index].y + sigmas[index]] } }); drawLine(chart, means); drawArea(chart, ranges); chart.render(); } } </script> </head> <body> <div id="chartContainer" style="height: 300px; width: 100%;"></div> <script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script> </body> </html> こちらは描画までしてみています. canvasJSでもとのsinの関数や、推定した関数、データ点などをプロットしています. おわりに 至らぬ点、間違い等あればご指摘いただければ幸いです.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カルーセル(HTML,CSS,jQueryで作成)

webページ作成でよく使用するカルーセルをコピペで作成できるようにコードをここにまとめます。 完成イメージ フォルダ構成 フォルダ構成は下のようにしています。 root/  ├ index.html  ├ styles.css  ├ main.js  └ img    ├ carousel1.jpg    ├ carousel2.jpg    └ carousel3.jpg 下のHTML、CSS、JavaScriptのコードをそのままコピペし、画像のURLを変えればそのまま使えます。 コード HTML HTML <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--CSSの読み込み--> <link rel="stylesheet" href="./styles.css"> </head>  <body> <div class="carousel">   <!--写真表示部分--> <ul class="carousel-area"> <li class="carousel-list"> <img class="carousel-img" src="img/carousel1.jpg" alt="carousel1"> </li> <li class="carousel-list"> <img class="carousel-img" src="img/carousel2.jpg" alt="carousel2"> </li> <li class="carousel-list"> <img class="carousel-img" src="img/carousel3.jpg" alt="carousel3"> </li> </ul>   <!--「次へ」「前へ」移動する矢印--> <div class="arrow-wrap"> <div class="arrow-left"> <button class="arrow-btn js-btn-back" type="button"></button> </div> <div class="arrow-right"> <button class="arrow-btn js-btn-next" type="button"></button> </div> </div>  <!--ページネーション--> <div class="pagination"> <span class="pagination-circle target"></span> <span class="pagination-circle"></span> <span class="pagination-circle"></span> </div> </div> <!--jQueryの読み込み--> <script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script> <!--javascriptファイルの読み込み--> <script src="./main.js" type="text/javascript"></script> <body> </html> CSS CSS * { margin: 0; padding: 0; -webkit-box-sizing: border-box; box-sizing: border-box; list-style: none; } body { overflow: hidden; } button { cursor: pointer; -webkit-appearance: none; -moz-appearance: none; vertical-align: middle; color: inherit; font: inherit; border: 0; background: transparent; padding: 0; margin: 0; outline: none; border-radius: 0; } .carousel { width: 600px; height: calc(600px * 0.5625); margin: 0 auto; position: relative; overflow: hidden; } .carousel .carousel-area { height: 100%; display: -webkit-box; display: -ms-flexbox; display: flex; position: absolute; } .carousel .carousel-area .carousel-list { width: 600px; height: calc(600px * 0.5625); margin-right: 30px; background-size: cover; background-position: center; background-repeat: no-repeat; } .carousel .carousel-area .carousel-list:nth-child(1) { background-image: url(./img/carousel1.jpg); } .carousel .carousel-area .carousel-list:nth-child(2) { background-image: url(./img/carousel2.jpg); } .carousel .carousel-area .carousel-list:nth-child(3) { background-image: url(./img/carousel3.jpg); } .carousel .carousel-area .carousel-list .carousel-img { width: 1px; height: 1px; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); margin: -1px; padding: 0; overflow: hidden; position: absolute; } .carousel .arrow-wrap { width: 96%; height: 100%; margin: 0 auto; position: absolute; top: 0; left: 2%; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } .carousel .arrow-wrap .arrow-btn { width: 48px; height: 48px; background-color: rgba(113, 135, 245, 0.8); border-radius: 50%; -webkit-transition: .2s; transition: .2s; } .carousel .arrow-wrap .arrow-btn:focus { -webkit-box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } .carousel .arrow-wrap .arrow-btn:hover { background-color: #334fd8; -webkit-box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } .carousel .arrow-wrap .arrow-left { position: relative; } .carousel .arrow-wrap .arrow-left button:before { content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-30%, -50%) rotate(-45deg); transform: translate(-30%, -50%) rotate(-45deg); } .carousel .arrow-wrap .arrow-right { position: relative; } .carousel .arrow-wrap .arrow-right button:before { content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-70%, -50%) rotate(135deg); transform: translate(-70%, -50%) rotate(135deg); } .carousel .pagination { width: 16%; margin: 5% auto 0; position: absolute; bottom: 3%; left: 42%; display: -webkit-box; display: -ms-flexbox; display: flex; -ms-flex-pack: distribute; justify-content: space-around; } .carousel .pagination .pagination-circle { width: 10px; height: 10px; border: 1px solid #333; border-radius: 50%; background-color: rgba(10, 10, 10, 0.5); } .carousel .pagination .pagination-circle.target { background-color: rgba(10, 10, 100, 0.8); } @media screen and (max-width: 600px) { .carousel { width: 300px; height: calc(300px * 0.5625); } .carousel .carousel-area .carousel-list { width: 300px; height: calc(300px * 0.5625); margin-right: 0; } } JavaScript JavaScript $(function(){ // スライドリストの合計幅を計算⇒CSSでエリアに代入 let width = $('.carousel-list').outerWidth(true); //.carouse-listの1枚分の幅 let length = $('.carousel-list').length; //.carousel-listの数 let slideArea = width * length; //レール全体幅=スライド1枚の幅 × スライドの合計数 $('.carousel-area').css('width', slideArea); //カルーセルレールに計算した合計幅を指定 //スライド現在値と最終スライド let slideCurrent = 0; //スライドの現在値(1枚目のスライド番号としての意味も含む) let lastCurrent = $('.carousel-list').length - 1; //スライドの合計数=最後のスライド番号 //スライドの切り替わりを「changeslide」として定義 function changeslide(){ $('.carousel-area').stop().animate({ //stopメソッドを入れることでアニメーション1回毎に止める left: slideCurrent * -width //代入されたスライド数 × リスト1枚分の幅を左に動かす }); //ページネーションの変数を定義(=スライド現在値が必要) let pagiNation = slideCurrent + 1; //nth-of-typeで指定するため0に+1をする $('.pagination-circle').removeClass('target'); //targetクラスを削除 $(".pagination-circle:nth-of-type(" + pagiNation + ")").addClass('target') //現在のボタンにtargetクラスを追加 }; //-----一定時間毎に処理実行する関数「startTimer」を定義 let Timer; function startTimer(){ Timer = setInterval(function(){ if (slideCurrent === lastCurrent){ slideCurrent = 0; changeslide(); }else{ slideCurrent++; changeslide(); }; }, 3000); }; function stopTimer(){ clearInterval(Timer); //crearInterval:setIntervalで設定したタイマーを取り消す }; startTimer(); //-----------ボタンクリック時の「changeslide」関数を呼び出し---------------- //NEXTボタン $('.js-btn-next').click(function(){ stopTimer(); startTimer(); if (slideCurrent === lastCurrent){ //現在のスライドが最終スライドの場合 slideCurrent = 0; changeslide(); //スライド初期値の値を代入して関数実行(初めのスライドに戻す) }else{ slideCurrent++; changeslide(); //そうでなければスライド番号を増やして(次のスライドに切り替え)関数実行 }; }); //BACKボタン $('.js-btn-back').click(function(){ stopTimer(); startTimer(); if (slideCurrent === 0){ //現在のスライドが初めのスライドの場合 slideCurrent = lastCurrent; changeslide(); //最後のスライド番号を代入して関数実行(最後のスライドに移動) }else{ slideCurrent--; changeslide(); //そうでなければスライド番号を減らして(前のスライドに切り替え)関数実行 }; }); }) 蛇足:CSS(SCSSバージョン) ※下のコードは不要です 下のコードは不要ですが、上のCSSコードは下のSCSSコードをコンパイルしたものですので、一応このコードもこちらに記載しておきたいと思います。 CSS *{ margin: 0; padding: 0; box-sizing: border-box; list-style: none; } body{ overflow: hidden; } button{ cursor: pointer; -webkit-appearance: none; -moz-appearance: none; vertical-align: middle; color: inherit; font: inherit; border: 0; background: transparent; padding: 0; margin: 0; outline: none; border-radius: 0; } .carousel{ width: 600px; height: calc(600px * 0.5625); margin: 0 auto; position: relative; overflow: hidden; .carousel-area{ // width: 3150px; height: 100%; display: flex; position: absolute; .carousel-list{ width: 600px; height: calc(600px * 0.5625); margin-right: 30px; background-size: cover; background-position: center; background-repeat: no-repeat; &:nth-child(1){background-image: url(./img/carousel1.jpg)}; &:nth-child(2){background-image: url(./img/carousel2.jpg)}; &:nth-child(3){background-image: url(./img/carousel3.jpg)}; .carousel-img{ width: 1px; height: 1px; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); margin: -1px; padding: 0; overflow: hidden; position: absolute; } } } .arrow-wrap{ width: 96%; height: 100%; margin: 0 auto; position: absolute; top: 0; left: 2%; display: flex; justify-content: space-between; align-items: center; .arrow-btn{ width: 48px; height: 48px; background-color: rgba(113, 135, 245, 0.8); border-radius: 50%; transition: .2s; &:focus{ box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } &:hover{ background-color: rgb(51, 79, 216); box-shadow: 0px 1px 10px -2px rgba(0, 0, 0, 0.8); } } .arrow-left{ position: relative; button:before{ content: ""; width: 10px; height: 10px; // cursor: pointer; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; transform: translate(-30%, -50%)rotate(-45deg); } } .arrow-right{ position: relative; button:before{ content: ""; width: 10px; height: 10px; border-top: 2px solid #fefefe; border-left: 2px solid #fefefe; position: absolute; top: 50%; left: 50%; transform: translate(-70%, -50%)rotate(135deg); } } } .pagination{ width: 16%; margin: 5% auto 0; position: absolute; bottom: 3%; left: 42%; display: flex; justify-content: space-around; .pagination-circle{ width: 10px; height: 10px; border: 1px solid #333; border-radius: 50%; background-color: rgba(10, 10, 10, 0.5); &.target{ // background-color: rgba(10, 10, 10, 0.8); background-color: rgba(10, 10, 100, 0.8); } } } } @media screen and (max-width: 600px){ .carousel{ width: 300px; height: calc(300px * 0.5625); .carousel-area{ // width: 1500px; .carousel-list{ width: 300px; height: calc(300px * 0.5625); margin-right: 0; } } } } 参考サイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PWAにアプリショートカットを導入したらほぼネイティブアプリになった。

こんばんは。ちょっとしたTipsでござる。 今回はPWAを更にネイティブアプリにすべくアプリショートカットを導入しましょう。 App-Shortcutとはアプリを長押ししてら出てくるやつのことです。 ↓こんなやつ アプリショートカットはChrome84からPWAでも使えるようになりました。 超簡単にユーザーの生産性向上につながると思うので実装したほうが良いかも知れませんってことでやりましょう。 今回は私のブログで導入してみました。 事前事項 詳細な仕様などは公式サイトを見てください。 ※PWA系の記事で毎回書いてるんですけどSSL対応が必須です。テストでやりたいならGitHub Pagesとかを使うといいかも知れません。 対応状況 対応しているプラットフォームは以下のとおりです。(2021/05/03現在) プラットフォーム 是非 Windows ○(Chrome85およびEdge85) MacOS × Android ○(Chrome85) iOS × ChromeOS △(記事下部参照) Apple系がまだ非対応ですね。 導入方法 導入はとてもかんたんでmanifest.jsonにshortcuts配列を追加するだけです。ServiceWorkerの変更とかも不要です。 manifest.json { "name": "Player FM", "start_url": "https://hoge.com", "shortcuts": [ { "name": "Open Play Later", "short_name": "Play Later", "description": "View the list of podcasts you saved for later", "url": "/play-later", "icons": [{ "src": "/icons/play-later.png", "sizes": "192x192" }] }, { "name": "View Subscriptions", "short_name": "Subscriptions", "description": "View the list of podcasts you listen to", "url": "/subscriptions", "icons": [{ "src": "/icons/subscriptions.png", "sizes": "192x192" }] } ] } 名前とURLだけは必須です。アイコン等はアプションですが設定しとくといいでしょう。 ※アイコンには現時点ではSVGファイルはサポートされていません。代わりにPNGを使用してください。 動作確認 ブラウザで確認 ちゃんと反映されてるか確認したい場合、ブラウザの開発者モードのApplicationタブでチェックで来ます。 Android Androidではネイティブアプリと同様に長押しで表示できます。設定したアイコンと名前、リンク先が反映されています。 Windows Windowsの場合はスタートメニューを右クリックもしくはタスクバーのアイコンを右クリックで表示できます。 MacOS Macはやっぱ非対応でした。 ChromeOS ChromeOSではChrome 92以降の実験機能で利用できるそうです。 chrome://flags/#enable-desktop-pwas-app-icon-shortcuts-menu-uiをONにするだけでできます。 公式より↓ かんたんなので皆さんも是非お試しあれ。 【ブログ】https://0115765.com/ 【Twitter】@tomox0115
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでテキスト入力チェック方法

JavaScriptでテキスト入力チェック方法です。 今回はテストプログラムでテストしています。 <!DOCTYPE html> <html lang="ja"> <style> body { padding:50px; background-color: greenyellow; } body #title { color:red; font-size : 50px; } body #name { width:200px; } body #mail { width:400px; } body #button1 { background-color: blue; } </style> <head> <meta charset="utf-8"> <title>sample</title> </head> <body> <h1 id = "title">送信フォーム</h1> <form action = "index4.html" method="POST"> Name:<input type="text" id="name"><br> Mail:<input type="email" id="email"><br> Detail:<textarea id="detail" value="detail" cols="50" rows="3" maxlength="150"></textarea></br> year:<select id = "year"> <option value="2021" id="2021">2021年</option> <option value="2022" id="2022">2022年</option> <option value="2023" id="2023">2022年</option> </select> month:<select id = "month"> <option value="1" id="1">1月</option> <option value="2" id="2">2月</option> <option value="3" id="3">3月</option> <option value="4" id="4">4月</option> <option value="5" id="5">5月</option> <option value="6" id="6">6月</option> <option value="7" id="7">7月</option> <option value="8" id="8">8月</option> <option value="9" id="9">9月</option> <option value="10" id="10">10月</option> <option value="11" id="11">11月</option> <option value="12" id="12">12月</option> </select> <input type="button" id="button1" value="送信" onclick="func1()"> </form> <div id="div1"></div> <script language="javascript" type="text/javascript"> //変数の定義 const name = document.getElementById('name'); const mail = document.getElementById('email'); const detail = document.getElementById('detail'); const button1 = document.getElementById('button1'); //入力チェック処理 const func1 = () => { if((name.value.length == 0 ) && (mail.value.length == 0 ) && (detail.value.length == 0 )){ alert('名前、メールアドレス、詳細が入力されていません。'); } else if ((name.value.length == 0 ) && (mail.value.length == 0 )){ alert('名前、メールアドレスが入力されていません。'); } else if ((mail.value.length == 0 ) && (detail.value.length == 0 )){ alert('メールアドレス、詳細が入力されていません。'); } else if ((name.value.length == 0 ) && (detail.value.length == 0 )){ alert('名前、詳細が入力されていません。'); } else if (name.value.length == 0){ alert('名前が入力されていません。'); } else if (mail.value.length ==0){ alert('メールアドレスが入力されていません。'); } else if (detail.value.length ==0){ alert('詳細が入力されていません。'); } else { if (window.confirm('送信してもよろしいですか?')) { div1.innerText = `Name:${name.value}、Mail:${mail.value}、Detail:${detail.value}、year:${year.value}、month:${month.value}`; } } } </script> </body> </html> length=0の部分でテキストに文字が入っていない場合はアラートメッセージで確認を促すようにしています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Discord BOTを特定チャンネルで呼びかけると反応するようにするメモ

久々にDiscrod BOTを触ってみてます。なんか前にも同じようなメモ書いた気もしてる... こんな感じにユーザーが発言したチャンネルによって処理のハンドリングをさせたいってメモです。 基本 自分用おさらいとしてメモ残しておきます。 Discord.jsのトップページのサンプルと一緒ですが、 サンプルの方はパッと見トークンをどこに入れれば良いのか分からないので注意。 Discrod.js const Discord = require('discord.js'); const client = new Discord.Client(); client.on('ready', () => { console.log(`Logged in as ${client.user.tag}!`); }); client.on('message', msg => { if (msg.content === 'ping') { msg.reply('Pong!'); } }); client.login(`アクセストークン`); client.login()の箇所に取得したアクセストークンを指定して起動すればOKです。 Webhook URLなど指定せずにローカルで試せます。 まずはこれでping/pongを試せます。 チャンネルの取得をしてハンドリング msg.channel.idでチャンネルのIDを指定するか、msg.channel.nameでチャンネル名を指定するかが良さそうです。 チャンネルIDの場合 チャンネルIDでハンドリングしたい場合はmsg.channel.idを利用します。 Discordのチャンネルを開いてる時のURLは以下のような形式です。 https://discord.com/channels/XXXXXX/YYYYYY このXXXXXXXの部分がサーバーごとのIDになり、YYYYYYの部分がチャンネルごとのIDになります。 ちなみにDMの場合は以下のような形式になります。 https://discord.com/channels/@me/YYYYYY URLの最後のYYYYYYがチャンネルIDになるので以下のようにハンドリング出来ます。 //省略 //特定の部屋での発言 if(msg.channel.id === 'YYYYYY'){ msg.channel.send('今日の会議の議事録はこちらです! https://hogehoge.com'); } //それ以外の部屋では反応しない else{ msg.reply('この部屋で設定されている会議はありません。'); } //省略 チャンネル名の場合 チャンネル名でハンドリングしたい場合はmsg.channel.nameを利用します。 ↑のように表示されてる名前です。ただ、この場合名前が合ってればという判定なので、運用で部屋の名前を変更した際などに想定している動作にならなくなるので注意が必要そうです。 //省略 //特定の部屋での発言 if(msg.channel.name === 'n0bi-playground'){ msg.channel.send('今日の会議の議事録はこちらです! https://hogehoge.com'); } //それ以外の部屋では反応しない else{ msg.reply('この部屋で設定されている会議はありません。'); } //省略 コード全体 const Discord = require('discord.js'); const client = new Discord.Client(); client.on('ready', () => { console.log(`Logged in as ${client.user.tag}!`); }); client.on('message', msg => { if (msg.content === 'ping') { msg.reply('Pong!'); } if(msg.content === '会議URL教えて'){ if(msg.channel.id === 'YYYYYY'){ msg.channel.send('https://hogehoge.com/hugahuga'); }else{ msg.reply('現在の部屋では設定されてるURLがありません。'); } } }); client.login(`アクセストークン`); 補足: 発言させるmsg.channel.sendとmsg.reply どっちもBOTを発言させるときですが、以下の違いがあります。 msg.channel.sendを使うとそのチャンネルでBOTが発言 msg.replyで発言者にリプライ付きでBOTが返信
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MicrosoftDocsに日英両方のテキストを表示する

概要 MicrosoftDocsはもうだいぶ前から英語で読むというトグルで気軽に日英切替できるようになりましたが、やはり日本語が怪しいと感じることがあります。 その度に英語に切替してもいいのですが、結構面倒ですしかといって最初から全部英語で読むのも語学力の関係で疲れます。 というわけで日英両方のテキストを両方表示するGreaseMonkey用スクリプトを作りました。 userscript microsoftdocs-bilingual.user.js // ==UserScript== // @name microsoftdocs-bilingual // @namespace https://gist.github.com/ryuix // @version 0.1 // @description dispalay ja-JP and en-US texts. // @author ryuix // @match https://docs.microsoft.com/ja-jp/* // @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js // @icon // @grant none // @noframes // ==/UserScript== $(function () { "use strict"; function addBlockQuoteStyle() { const head = document.getElementsByTagName("head")[0]; if (!head) { return; } const style = document.createElement("style"); style.type = "text/css"; style.innerHTML = `.biLangBlockQuote { border-radius:6px; border:1px solid; background-color: #efefef; border-color:#efefef !important; margin:0.3em 0 !important; display:block;}`; head.appendChild(style); } function addVisilityButton() { if (document.getElementById("biLangToggle")) { return; } const button = document.createElement("input"); button.id = "biLangToggle"; button.type = "button"; button.value = "switch"; button.style.position = "fixed"; button.style.top = "90%"; button.style.right = "1em"; const blocks = document.querySelectorAll("blockquote.biLangBlockQuote"); button.addEventListener("click", () => { for (const element of blocks) { if (element.style.display === "none") { element.style.display = "block"; } else { element.style.display = "none"; } } }); document.querySelector("body").append(button); } // https://qiita.com/nagtkk/items/e1cc3f929b61b1882bd1 function groupBy(array, getKey) { return Array.from( array.reduce((map, current) => { const key = getKey(current); const list = map.get(key); if (list) list.push(current); else map.set(key, [current]); return map; }, new Map()) ); } const enDescriptions = document.querySelectorAll("span[data-stu-id]"); if (enDescriptions.length === 0) { return; } addBlockQuoteStyle(); const paragraphGroup = groupBy( Array.from(enDescriptions), (x) => x.parentNode.parentNode ); for (const paragraph of paragraphGroup) { const fragment = document.createDocumentFragment(); for (const span of paragraph[1]) { fragment.appendChild(span); } const quote = document.createElement("blockquote"); quote.className = "biLangBlockQuote"; quote.appendChild(fragment); paragraph[0].appendChild(quote); } addVisilityButton(); }); 使い方 下図のように段落毎に英語テキストが表示されます。 邪魔な場合は右下のswitchボタン(ださい…)を押すと通常の一言語表示に戻ります。 Gist
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

switch文

switch文 if文以外の条件分岐の方法として、switch文があります。switch文は「ある値によって処理を分岐する」場合に用いることができます。 記述は「switch(条件の値){処理}」のように記述します。 例 const rank= 1; switch(rank){ case 1: //caseの末尾は:(コロン)を用います console.log('金メダルです'); break; case 2: console.log('銀メダルです'); break; } 出力結果 金メダルです 上記のように記述することで、出力結果を得ることができました。 switch文の中にcaseを追加することで処理を分けることができます。 上記のように定数rankの値が1の時、「金メダルです」が出力されるようになっています。 また、breakも非常に重要であり、switch文を終了する命令を出す役割があります。 breakが無いと、合致したcaseの処理を行った後、その後のcaseの処理も実行されてしまいます。 仮に上記の「case 1:」の処理後に「break;」 がなかった場合、その後のcaseの処理である「銀メダルです」も実行されてしまいます。 よって、breakを忘れず記述する必要があります。 default switchの条件の値がcaseのどれにも一致しなかった時、defaultのブロックが実行されます。 イメージとしては、if文のelseと似ているのではと考えています。 例 const rank= 4; switch(rank){ case 1: //caseの末尾は:(コロン)を用います console.log('金メダルです'); break; case 2: console.log('銀メダルです'); break; case 3: console.log('銅メダルです'); break; default: console.log('メダルはありません'); break; } 出力結果 メダルはありません 上記のように記述することで、定数rankの値がどのcaseの値にも一致しなかったので、 defaultの処理が実行されました。 仮に上記をif文で記述した場合、 if文 const rank = 4; if(rank == 1){ console.log('金メダルです'); } else if(rank == 2){ console.log('銀メダルです'); } else if(rank == 3){ console.log('銅メダルです'); } else { console.log('メダルはありません'); } 出力結果 メダルはありません 上記のように記述することになります。 分岐が多く複雑な場合、switch文で書き換えるとシンプルで読みやすいコードにできます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今から学ぶReduxの基礎(概要編)

Reduxとは 一言で言うと、「state(状態)を管理をするためのライブラリ」となります。 しかし、これだけだと何も分からないので順を追って説明していきます。 状態管理とは まず、状態管理とは何かを簡単に説明します。 例としてアプリケーションには、以下のような情報を保持する場合があります。 ユーザーがログインしている チェックボックスがチェックされている モーダル が表示されている これらの情報を「状態」と呼び、状態管理とはこれらの情報を管理するものです。 Reactで状態を管理する方法とReduxを使う理由 Reactで状態を管理する方法 Reactで状態を管理する方法として、以下のようなものがあります。 関数コンポーネントでReact HooksのuseStateを使用 クラスコンポーネントを使用 useStateに関して、詳しくは以下を参照 https://qiita.com/seira/items/f063e262b1d57d7e78b4 これらはローカルステートと呼ばれています。 Reduxを使う理由 では、なぜReactで状態を管理する方法があるのにReduxを使うのか。 その理由として、コンポーネントを跨いで状態を共有したいと思った時にローカルステートでは以下の方法で状態を共有する必要があります。 上位のコンポーネントに必要な状態を全て持たせる 上位のコンポーネントから子、孫コンポーネント必要な情報バケツリレーしていく しかし、この方法だと以下のような問題が発生します。 どんどんコードが複雑化していく 親子関係のないコンポーネント間では状態を共有することができない これらの解決策としてReduxを使うことができます。 Reduxで何ができるのか Reduxを利用することで、コンポーネントの親子関係の有無に関わらず複数のコンポーネントからアクセスできるステート(グローバルステート)を作ることができます。 ※ その他にも色々あるが、ここでは省略 Reduxの登場人物とデータフロー Reduxを理解する上で避けては通れない言葉や概念を解説していきます。 登場人物 Store アプリケーションの全ての状態を保持するオブジェクト { value: 0, } Action 「何が起きたのか」という情報を持ったオブジェクト 以下の例では、deposit(入金)と入金金額を表したアクションを作成しています { type: 'deposit', payload: 10 } Action Creater Actionを作成するメソッド 毎回Actionを書くのは手間であり、typo時にバグの原因にもなるため指定されたActionを返すメソッドを作成する const deposit = (value) => { return { type: 'deposit', payload: value } } Reducer stateとActionを受け取り、変更したstateを返す純粋関数(同じ引数を渡せば、毎回必ず同じ結果を返す関数) const reducer = (state = [], action) { switch (action.type) { case 'deposit': return { ...state, value: action.payload }; default: return state; } } dispatch 発送(する)、派遣(する)などの意味を持つ英単語 ActionをStoreに送る役目を担う 以下の例では、ボタンがクリックされた時にdepositというActionをStoreに送る <button onClick={()=>{ dispatch(deposit()) }}>$10を入金</button> データフロー ここまでコードと文章でまとめましたが、なかなか理解しづらいので処理の流れを図で表したものを紹介します。 (引用元:https://redux.js.org/tutorials/essentials/part-1-overview-concepts#redux-application-data-flow) 上の図はイベントによってUIに表示されている\$0という状態を\$10という状態に変更しています。 (UIと書いてある部分が普段私たちが見ている画面の表示部分です) これをもとにstateが更新される流れを順に見ていきましょう。 クリック等のイベントが起きるとreducerに向けてActionをdispatch(送信)します reducerは現在のstateとActionを受け取り、新しいstateを作成します 最後にUIの表示変更をして終わりです Reduxの三原則 Reduxは公式ドキュメントで以下の3つの原則を掲げています。 Single source of truth(信頼できる唯一の情報源) Reduxでは複数の状態を一元管理させることで、デバッグのしやすさを実現しています State in read-only(stateは読み取り専用にする) 状態を直接変更するのではなく、actionを発行します Changes are made with pure functions(変更はすべて純粋関数で行われる) 同じ引数を渡せば、毎回必ず同じ結果を返す関数で状態の変更を行います
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GAS + Vision APIで記録会のタイム入力を半自動化する

スイマーによるスプリント系スポーツのための日曜プログラミングシリーズ第4弾。そういえばタイムの成型の話以降は別にスプリントに限った話でもなかった。 もはや第3弾を超え、平日の定時後もつぎ込まれる大作となりました(在宅勤務で行後の時間がたっぷりとれたのも一因)が「おしごとではない」という意味で「日曜プログラミング」の名前は残しておくことにします。 前置き さて、前回記事の「超速報」は仕組みとしては想定通りに動き、掲示を見に行かなくても結果が見られる・閉会後も他の人の記録含めてスマホから見返せるということでそこそこ評判のようでした。 ところがどっこい、このときは自分がシステムの一部となってしまいPCから離れられず。もともと出場予定なかったからよかったけど、次の大会は自分も出るのである程度省力化しておかないとビショビショのままタイム入力に駆け戻ることになりかねない(プールサイドを走ってはいけません)。 これはSEとしてはあるまじき失態ぞ……ということでGoogleのCloud Vision APIを使ってOCR機能を作ることにしました。 作ったもの・使った技術 大まかな構成 入力用WEBページ(カメラ読み取り、OCRリクエスト、OCR結果取得と加工、加工済みデータの登録) Google Spread Sheet + Google Apps Script(加工済みデータのストレージ、外部公開用API) 公開用WEBページ(Vue.jsでGASから取得したデータを公開) このうちGASの外部公開用APIと公開用WEBページは前回記事で作成済みのもの。 カメラ台の作成 どしょっぱなは工作です。図工好きよ。 OCRに回すことを考えると可能な限り歪みのない画像を取得する必要があるので、PCのモニタ上にについているようなカメラでは撮影が難しい。 自炊クラスタのようにカメラを固定して原稿を差し入れる構造にしたかったので、スマホを外付けカメラモジュールとして使用できるIriun Webcamを使用し、さらに撮影用の台を用意することにしました。 Seriaのワイヤー整理棚(大きいほう)を買ってきてスマホを乗せると、天板のワイヤーの隙間からいい感じの距離感で棚の下のレシートを撮影できます(レシート全体が映らないといけないので、距離は結構大事)。 さらにレシートはロールから出てきたばかりで基本的に丸まっているので、硬質カードケース(B4)の1辺を切り出して「レシート平らにするやーつー」を作成。これにレシートを入れたうえで棚の下に差し入れることで、きれいな矩形のレシート画像が撮れる。整理棚とカードケースで合計200円。やっす。 あと、光源との位置関係によってはレシートに影が落ちてしまって精度が下がるので、棚の周囲にカーテン的なものを張ったほうがいいです。私は今回その辺にあったコピー用紙で棚を囲みました。 カメラ映像の取り込みと撮影 HTMLで既存の画像以外のものを扱うのは初めてだったので、カメラにアクセスするところから先人のお知恵を拝借します。 参照:[HTML5] カメラをJSで操作し写真を撮影する 画像を回転 スマホカメラの画像が横長の映像として取得されるので、レシート(縦長)の全体をおさめかつOCRできる向きにするため、画像を回転します。 参照1:【Javascript】video/canvasを上下180度反転(回転)させる方法 【お家IT#10】 参照2:rotate(angle) - Canvasリファレンス (この回転があるせいでブラウザ上の要素の配置が非常に面倒になったんですがそれはそれとして) フィルタの適用 せっかくなのでOCR制度を向上するため、フィルタを適用してみました。 参照:Canvasを用いた9つの画像処理フィルターとそのアルゴリズムの解説|Black Everyday Company 画像を送る準備 Cloud Vision APIに画像を送るためには、いったんbase64文字列に変換する必要があるということでこちらも拝借。 参照:HTML5 の canvas 要素を base64 文字列化し画像として保存する方法まとめ OCR結果の取得 レシートは通常の文章と違って文字間が開いているので、OCRが返してくる結果のblockやparagraphはあまり使い物になりません。そこで結果の1文字ずつの位置情報を使って行を分割、行内の順番を整理して「行ごと」のデータを作成します。 さらに行内の表示内容はルール化されているため、文字数ベースで行内のセルを分割していきます。ついでによくある読み取りミスも修正してしまう。レシートのフォーマットは前回記事参照。 all.js //得られた結果を画面に表示する function showResult(result){ //解析結果をオブジェクトに格納 doc = []; bounds=[]; doc = result.responses[0].fullTextAnnotation; for(var page of doc.pages){ for(var block of page.blocks){ for(var paragraph of block.paragraphs){ for(var word of paragraph.words){ for(var symbol of word.symbols){ var x = symbol.boundingBox.vertices[0].x; var x2 = symbol.boundingBox.vertices[1].x; var y = symbol.boundingBox.vertices[3].y;//小数点の所属行を正確に判定するため、Y位置は左下を取得する var t = symbol.text; bounds[bounds.length]={"x":x, "x2": x2, "y":y, "t":t}; } } } } } sort(); } function sort(){ bounds.sort(function(a, b) { if (a.y < b.y) { return -1; } else { return 1; } }); var oldY = -1; var line = []; var lines = []; var str = ""; var strings = ""; var threshold = Number(document.getElementById("Ythreshold").value);//改行検出閾値 console.log("Y-threshold:" + threshold ); var singleLine = ""; for(var bound of bounds){//各行内ソート処理 if(oldY == -1 || (oldY - threshold <= bound.y && bound.y <= oldY + threshold)){ //一番最初の文字もしくは同一行内 oldY = bound.y; line[line.length]=bound; }else{//行切り替え時処理(前行のプッシュ) //line内ソート line.sort(function(a, b) { return (a.x < b.x)? -1:1 }); //行内文字全結合 for(var s of line){ singleLine = singleLine + s.t; } console.log(singleLine); //行種類判定 if(singleLine.substr(1,1)=="P" || singleLine.substr(1,1)=="p"){ //ラップ見出し(P L TURN TIME) }else if(singleLine.search("M")!=-1 || singleLine.search("LAP")!=-1 || singleLine.search("GOA")!=-1 || singleLine.search("OAL")!=-1){ //ラップ見出し(xxM LAP) }else{ //タイム行 lines[lines.length]=[found1(singleLine.substr(0,1)), found1(singleLine.substr(1,1)), found1(singleLine.substr(2,1)), timeFIX(singleLine.substr(4))];//line; str = lines[lines.length-1].join(' '); if(strings.length==0){ strings = str; }else{ strings = strings + '\n' + str; } //strとstringsはlog参照用 str = ""; } line = []; oldY = bound.y; singleLine = bound.t; singleLine = ""; line[line.length]=bound; //元データ保持用 } } //最終行処理 //line内ソート line.sort(function(a, b) { return (a.x < b.x)? -1:1 }); //行内文字全結合 for(var s of line){ singleLine = singleLine + s.t; } console.log(singleLine); //行種類判定 if(singleLine.substr(1,1)=="P" || singleLine.substr(1,1)=="p"){ //ラップ見出し(P L TURN TIME) }else if(singleLine.search("M")!=-1 || singleLine.search("LAP")!=-1 || singleLine.search("GOA")!=-1 || singleLine.search("OAL")!=-1){ //ラップ見出し(xxM LAP) }else{ //タイム行 //linesに追加 lines[lines.length]=[found1(singleLine.substr(0,1)), found1(singleLine.substr(1,1)), found1(singleLine.substr(2,1)), timeFIX(singleLine.substr(4))];//line; str = lines[lines.length-1].join(' '); if(strings.length==0){ strings = str; }else{ strings = strings + '\n' + str; } //strとstringsはlog参照用 str = ""; } console.log(lines); viewTable(lines); } 参照:【Google Colab】Vision APIで『レシートOCR』 OCR結果の修正 一発で100%取得できるとも限らないし、ソフトタッチ等々でレシートにタイムが出てこないこともあるので、OCR後の編集もブラウザ上でできるようにしたい……とおもってGoogle先生にお伺いを立てたらコレだよ。 参照:contenteditable - HTML: HyperText Markup Language | MDN どうかんがえても使わざるを得ない。惜しいのはタブでセルの横移動ができないことですね。javascriptゴリゴリ書いたらできるのかな。 データの登録 編集完了したらヘッダ項目(泳法・距離・組)を追加して、以前作成したGoogleスプレッドシートの結果速報シートに転記する。 all.js var classname = $('#racedata [name=classname]:checked').val(); var distance = $('#racedata [name=distance]:checked').val(); var grpnumber = $('#racedata [name=grpnumber]').val(); var postDat = []; var rowDat = {}; var tbl = document.getElementById('editTable'); for(var row of tbl.rows){ if(row.cells[0].firstChild.innerText != ''){ rowDat = {"distance":distance, "class":classname, "group":grpnumber, "lane":row.cells[1].firstChild.data, "turn":row.cells[2].firstChild.data, "time":row.cells[3].firstChild.data }; postDat[postDat.length] = rowDat; } } var url = "https://script.google.com/macros/s/APIキーがここに入る/exec"; var postParam = { "method" : "POST", "mode" : "no-cors", "Content-Type" : "application/x-www-form-urlencoded", "body" :JSON.stringify(postDat) }; fetch(url, postParam); $('#editTable').empty(); video.play(); video.style.display="block"; canvas.style.display="none"; なお、POSTでGASを経由してスプレッドシートにJSONを投げ込もうとしたらCORS (Cross-Origin Resource Sharing) に躓いたので、こちらの記事を参考に投げ方を修正。POSTは無理っすわーっていう記事が多かった中で大変助かりました。 参照:[備忘録] GASのdoPost()にJavaScriptからJSONを渡す方法 - Qiita 完成! インクリボン交換直後とか、笑っちゃうくらい読み取り精度が高くてほぼ修正不要でした。何なら人間が見間違える0と8を読み分けてきたりする。一方でインクが薄れてくるとどうしても文字が読み取りにくくなるので人間の視覚って高度だなと思った次第。 入力の手間が省けたので無事自分のレースにも参加できて、もともと担当じゃなかったはずの当日のエントリーを組分けする作業をしていたら結局2レース目は棄権してしまった(あれ???)(運営人員少なすぎではないか???) ということで次回はエントリーの組分けを楽にする仕組みを作るぞ(涙)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  繰り返し処理 何回も書くのがめんどくさい! 繰り返しの文  私初心者なので 復習

for文 繰り返し処理を行う方法として、while以外にもfor文がある。 for(変数の定義;条件式;変数の更新) {  ↑セミコロン 処理 }←ここにはセミコロンは不要 let number = 1; 変数の定義 while (number <= 100) {      *()の中は条件式 console.log(number); number += 1;  ↑変数の更新 } //for文 例 for (let number = 1; number <= 100; number += 1) { //↑変数の定義    ↑条件式     ↑変数の更新 console.log(number); } 計算式の省略 足し算 number = number + 1 →進化 number += 1 → number++ 引き算 number = number - 1 →進化 number -= 1 → number-- for (let number = 1; number <= 100; number ++) { //      ↑変数の更新++省略して書けた console.log(number); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HerokuにNodeJsアプリをデプロイする際に確認すべき4つのポイント

1.ポート設定 index.js const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log("Server up!!") }) 2.使用中のNode,NPMバージョンの指定 package.json "engines": { "node": "使用中のバージョンを記載(14.15.0など)", "npm": "使用中のバージョンを記載(7.7.6など)" } 3.開始スクリプトの指定 package.json "scripts": { "start": "node index.js" } 4.gitignoreファイルの作成 .gitignore node_module etc..
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クレジットカードの読み取り機能を実装する!

はじめに 先日、クレジットカードをiPhonのカメラで読みとり、入力フォームに自動で入力される機能の実装を行なったので記事を書きます! この機能の実装自体は難しくなかったですが、httpsで接続していないとこの機能は動かないみたいで、動作を検証する際に悩みました。。 やりたいこと 以下画像のように、クレカ読み取り機能で、クレカを枠内に入れたらフォームにクレカ情報が自動的に入力されるようにしたい。 ※注意 ・読み取れる項目は、カードナンバーと有効期限とカードのタイプのみのようです。名前とCVVは手動で入力する必要があります。 (今回は、カードナンバーと有効期限のみ) ・iOS8以上でないと、読み取り機能は正常に機能しないみたいなので注意が必要です! ・Angularのアプリケーション内で実装したのですが、Angular Materialの mat-selectタグを使用すると上手く行かなかったので、通常のselectタグを使用しました。→ mat-selectタグでも実装できた人教えてください!笑 環境 環境はこんな感じです。 $ ng version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ Angular CLI: 11.0.7 Node: 14.15.1 OS: darwin x64 Angular: 11.0.9 ... animations, common, compiler, compiler-cli, core, forms ... platform-browser, platform-browser-dynamic, router Ivy Workspace: Yes Package Version --------------------------------------------------------- @angular-devkit/architect 0.1100.7 @angular-devkit/build-angular 0.1100.7 @angular-devkit/core 11.0.7 @angular-devkit/schematics 11.0.7 @angular/cli 11.0.7 @schematics/angular 11.0.7 @schematics/update 0.1100.7 rxjs 6.6.7 typescript 4.0.7 実装 View側 特別な実装は以下の3点かと思います。 ・カードナンバーフォームのname属性として、「"cardNumber"」を指定する。 ・有効期限(月)フォームのname属性として、「"cardExpirationMonth"」を指定する。 ・有効期限(年)フォームのname属性として、「"cardExpirationYear"」を指定する。 <form [formGroup]="paymentForm" (ngSubmit)="onSubmit()"> <div> <input id="cardNumber" name="cardNumber" formControlName="cardNumber"><br><br> </div> <div> <select formControlName="expiration_month" name="cardExpirationMonth"> <option *ngFor="let m of monthList"> {{ m + '月'}} </option> </select> <select formControlName="expiration_year" name="cardExpirationYear"> <option *ngFor="let key of yearList">{{ key }}</option> </select> </div> <button type="submit">決定</button> </form> コンポーネント側 通常のReactvieFormを作成するのと特に変わっていることはありません。 import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-counter', templateUrl: './counter.component.html', styleUrls: ['./counter.component.scss'] }) export class CounterComponent implements OnInit { // セレクトタグのフォームの部品となる「月」の配列 public monthList = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]; // セレクトタグのフォームの部品となる「年」の配列 public yearList = [2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031]; public paymentForm: FormGroup; constructor( private fb: FormBuilder ) { } ngOnInit(): void { this.paymentForm = this.fb.group({ 'cardNumber': ['', [Validators.required]], 'expiration_month': ['', [Validators.required]], 'expiration_year' : ['', [Validators.required]] }) } // 一旦入力された値をコンソールログに出力する。 public onSubmit(): void { console.log(this.paymentForm.get('cardNumber').value); console.log(this.paymentForm.get('expiration_month').value); console.log(this.paymentForm.get('expiration_year').value); } } ローカル環境での動作確認 これでフォームとしては、機能しますがhttpsで接続していないと機能しません。なので、ローカル環境での検証をどうしようかなと調べました。どうにかして、ローカル環境にhttps接続したい。。。 調べた結果... ngrokというライブラリを使用すると、ローカル環境にhttpsで接続することができます! ※ローカル環境にどこからでもアクセスできるようになってしまう為、セキュリティー的には危険です。その辺りを意識しながら使用してください。 さっそくインストール! $ brew install ngrok --cask バージョンが確認できればインストール完了です。 $ ngrok -v $ ngrok version 2.3.39 ローカル環境にhttps接続する為には以下のコマンドを実行します。 # ポート番号は自分が立ち上げているアプリケーションのポート番号を指定 $ ngrok http 4200 -host-header="localhost:4200" 上記コマンドを実行したら、下記のように表示されます。 スマホでSafariを開き、ForwardingのURLをアレスバーに入力すると、ページが表示されるはずです。 ngrok by @inconshreveable (Ctrl+C to quit) Session Status online Session Expires 1 hour, 59 minutes Version 2.3.39 Region United States (us) Web Interface http://127.0.0.1:4040 Forwarding http://acf3da528cdc.ngrok.io -> http://localhost:4200 Forwarding https://acf3da528cdc.ngrok.io -> http://localhost:4200 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 httpsで接続して、inputフォームをクリックする、以下の画像のように入力欄が表示され、「クレジットカードを読み取る」という項目が表示されます。 この項目をクリックするとカメラが起動して、以下の画像のような表示になります。 枠内にクレジットカードを入れるとフォームに自動的に、カード番号、有効期限が入力されます。 これで実装とローカルでの動作確認は終わりです! まとめ クレジットカードの読み取り機能は、もう少し難しい実装になると思いましたが、案外簡単にできました。 ローカル環境にhttps接続する方法もついでに学べたので、よかったです。 ngrokではなく、serveoというサービスを使用してもできるようですので、今度はそちらを触ってみようかと思っています。 何か間違えている部分やこうしたほうが良いってところがあれば、コメント等で教えて頂ければ嬉しいです! 参考 クレカ読み取りについて https://qiita.com/okumura_daiki/items/c5c28117b999252e22ca ngrokについて https://qiita.com/T-Com/items/7f1468167f80df00a87d https://qiita.com/kitaro0729/items/44214f9f81d3ebda58bd https://www.mathkuro.com/mac/brew-cask-command-error/ serveoについて https://qiita.com/kaba/items/53b297e2bfb5b4f20a48
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  while文 何回も書くのがめんどくさい! 繰り返しの文  私初心者なので 復習

前にも書いたかもしれないですが、復習なのでもう一度。 while文 1から100まで数字を出力したい時のwhile文 let number = 1; console.log(number); number += 1; console.log(number); number += 1; console.log(number); number += 1; console.log(number); number += 1; console.log(number); number += 1; これ100回かく???めっちゃ嫌なんですけど・・・・ let number = 1; while (条件式) { console.log(number); number += 1;//{}波括弧の中に、繰り返す処理を一回だけ書くのみでOK! } //いつまで繰り返すのかも入れないとね! let number = 1; while (number <= 100) {//変数numberの値が100以下の時に繰り返して処理しますー console.log(number);//繰り返す処理はこの2行 number += 1; } trueであれば指定の時まで繰り返し処理するよ while文には、条件式の結果がいつかはfalseになり、繰り返し処理が終わるよ。 コードの書き忘れで無限ループが発生してしまうこともあるので注意!!!!! let number = 1; while (number <= 100) {//変数numberの値が100以下の時に繰り返して処理しますー console.log(number);//繰り返す処理はこの2行 //number += 1;ここ書かないと・・・無限に1がコンソールにお目見えします }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS~クリックゲーム~

概要 ①初期 上記の画像をゲーム開始とします。 ②ゲーム開始 ②のようにボタンを押すと、OKが出てくるゲームを作成しました。 なお、1回目のクリックののときにリストが削除するよう実装しました。 ①タイトル 1,HTML index.html <div class=header> <h1 class="title">ToDo!!</h1> </div> 2,CSS style.css .title { padding-left:60px ; cursor: pointer; } .title2 { border-bottom:3px solid greenyellow; font-size: 50px; color: red; transform:rotateZ(20deg); } 3,JS main.js const title = document.querySelector('.title'); console.log(title); title.addEventListener('dblclick',()=>{ title.classList.toggle('title2'); }); ダブルクリックイベント発生で、title2クラスを設定します。ただし、クラスの付け外しを行いたいのでtoggleメソッドを使用します。 ②ゲーム 1,HTML index.html <button>ボタン</button> <ul class="ul"> <li class="lis" >リスト</li> </ul> 2,JS main.js let count = 0; const button = document.querySelector('button'); button.addEventListener('click',() =>{ count += 1; if(count === 1) { const ul2 = document.querySelector('.ul'); const lis =document.querySelector('.lis') ul.removeChild(lis); } const makeLi = document.createElement('li'); makeLi.textContent = 'ok'; const ul = document.querySelector('ul'); ul.appendChild(makeLi); makeLi.classList.toggle('list'); }); 1,remove.child(); letに0を代入します。 1回目のクリックでHTMLのli要素のリストを削除します。 親要素のulを取得します。削除するクラスlisを取得します。 ul.removeChild(lis)で子ノードを削除します。 2,document.createElement(); 新たに、li要素を生成していきます。 document.createElement('li')メソッドで空の要素を生成します。 空の要素にokを中身の要素に追加します。 3,appendchaild(); li要素をulの子ノードとして追加します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのsortとreverseで勘違いしていたこと

 ちょっと用事があって、JavaScriptをしたところ、しばらく悩んでしまいました。  それは、数値の降順ソートです。  たとえば、 var arr = [1, 2, 5, 4, 3]; arr.reverse(); で、降順ソート結果 5, 4, 3, 2, 1 を期待というか、勝手に確信してしまっていたのですが、 3, 4, 5, 2, 1 になることに気が付かず、時間を食ってしまいました。  数値の降順ソートをするには、 var arr = [1, 2, 5, 4, 3]; arr.sort(); arr.reverse(); なんですね。 ※当たり前といえば、当たり前過ぎですね。 ※node.jsで試しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OBS配信用テロッパー

<!DOCTYPE html> <html lang="ja"><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script> $(e=>{ var b = new OBS.Browser().addLayer( OBS.layer.map(a=>{ return new OBS.Layer(...a) }) ).addControl( new Controller.Status() ) }) var OBS = { layer:` RB, NHK.png LB, Cover.png B, Shanghai.png LEFT, Zombie.png START, Shuchu2.svg X, Zawa.png Y, Pumpkin.png A, Shuchu1.svg RIGHT, NameCard.png UP, Cloud.png DOWN, Frame.png `.trim().split(/\s*\n+\s*/).map(s=>{ return s.trim().split(/\s*,\s*/) }) } function _html(...a){ var b = a.shift().split('.') var q = $('<'+(b.shift()||'div')+'>').addClass(b) return q.append(a) } OBS.Browser = class{ constructor(...a){ this.layer = {} $('body').append( this.view = _html('.Browser', this.$Layers = _html('.Layers') ) ) this.loop = [] setInterval(e=>{ this.loop.forEach(c=>c.loop()) },1000/30) } addLayer(a){ a.forEach(v=>{ this.$Layers.prepend(v.view||null) this.layer[v.type] = v }) return this } addControl(...a){ a.forEach(c=>{ if(c.loop) this.loop.push(c) c.on(e=>{this.on(e)}) }) return this } on(e){ if(e.type=='down'){ var v = this.layer[e.key] if(v) v.view.toggle() } console.log(e) } } OBS.Layer = class{ constructor(k,v){ this.type = k this.view = _html('.Layer.'+v).hide() this.view.css('background-image',`url(img/${v})`) } } var Controller = {} Controller.Data = class{ constructor(){ this.buttons = this.buttons() this.axes = this.axes() this.count = 0 this.connection = {} this.listener = console.log this.dummy = { buttons:this.buttons.map(k=>{return {pressed:false}}), axes:this.axes.map(k=>{return 0}) } } buttons(){return 'A,B,X,Y,LB,RB,LT,RT,SELECT,START,LS,RS,UP,DOWN,LEFT,RIGHT'.split(',')} axes(){return 'LX,LY,RX,RY'.split(',')} button(a,b,i){ if(a.pressed==b.pressed) return null switch(b.pressed){ case(true): this.listener({type:'down', key:this.buttons[i]});break default: this.listener({type:'up', key:this.buttons[i]}) } } stick(a,b,i){ if(a==b) return null var p = this.axes[i]+'_POSITIVE' var n = this.axes[i]+'_NEGATIVE' switch(true){ case(a>0): this.listener({type:'up', key:p});break case(a<0): this.listener({type:'up', key:n});break } switch(true){ case(b>0): this.listener({type:'down', key:p});break case(b<0): this.listener({type:'down', key:n});break } } move(axes,s){ if(axes.filter(v=>Math.abs(v)>0.2).length==0) return null this.listener({type:'move',axes:axes,stick:s}) } } Controller.Status = class extends Controller.Data { constructor(){super() window.addEventListener("gamepadconnected",e=>{ console.log(e) this.count++ this.status(e.gamepad) }); window.addEventListener("gamepaddisconnected",e=>{ console.log(e) this.connection[e.gamepad.index] = null this.count-- }); this.gamepadAxes = [] } on(f){ this.listener = f return this } loop(){ if(this.count==0) return this.item = Array.prototype.slice.call(navigator.getGamepads()) this.item.forEach(g=>this.status(g)) return this } status(gamepad){ if(gamepad == null) return var g = this.connection[gamepad.index]||this.dummy gamepad.buttons.slice(0,16).forEach((v,i)=>this.button(g.buttons[i],v,i)) gamepad.axes.forEach((v,i)=>this.stick(Math.round(g.axes[i]),Math.round(v),i)) this.move(gamepad.axes.slice(0,2),'LeftStick') this.move(gamepad.axes.slice(2,4),'RightStick') this.connection[gamepad.index] = gamepad this.gamepadAxes = gamepad.axes } } </script> <style> *{margin:0;padding:0;} .Layer{ width:1920px;height:1080px; position:absolute;top:0; background-size:cover; background-repeat: no-repeat; background-position: 50% 50%; } /* thx https://qiita.com/seahorse_saki/items/e064760f82832ff766bc */ @keyframes pyon01 { 0%, 100% {transform: translate(0, 0);} 50% {transform: translate(0, -100px);} } @keyframes bikkuri01 { 100%,60%,35%,25%,0% {transform: translateY(0);} 30% {transform: translateY(-26px);} 40% {transform: translateY(-15px);} } @keyframes buruburu01 { 0% {transform: translate(0, 2px) rotateZ(0deg);} 25% {transform: translate(2px, 0) rotateZ(1deg);} 50% {transform: translate(2px, 2px) rotateZ(0deg);} 75% {transform: translate(2px, 0) rotateZ(-1deg);} 100% {transform: translate(0, 0) rotateZ(0deg);} } .Layer.Zawa{ animation:buruburu01 .1s infinite; } .Layer.Pumpkin{ animation:pyon01 2s ease-in-out infinite; } .Layer.Zombie{ top:200px; animation:pyon01 3s ease-in-out infinite; } .Layer.NameCard{ animation: bikkuri01 3s both infinite; } </style> </head> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  switch文  私初心者なので 復習 ②

何にも該当しない場合 default const color = "赤"; switch (color) { case"緑": case"黄色": case"青": default: console.log("colorの値が正しくありません");→何も当てはまらない時 これがコンソールに出るよ break; } if文・else if とかよりもswitchの方がシンプルで読みやすいコードになるんだって
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript ボタン要素にonclick属性を追加する

追加方法 Attributeとして追加する setAttributeで追加する。 <button id="button">ボタン</button> const button = document.getElementById('button'); button.setAttribute('onclick', 'pushButton()'); ※メソッド名の後の括弧を忘れないようにする ページ読み込み後 <button id="button" onclick="pushButton()">ボタン</button> Propertyとして追加する onclickプロパティに追加する。 <button id="button">ボタン</button> const button = document.getElementById('button'); button.onclick = pushButton; ※メソッド名の後の括弧は不要 addEventListenerで追加する addEventListener第一引数にはonclickではなく、clickを渡す。 <button id="button">ボタン</button> const button = document.getElementById('button'); button.addEventListener('click', pushButton); ※メソッド名の後の括弧は不要 コメントについて mikawanaさんから頂いたコメントについて追記します。 上書きと追加 Attribute と Property によるクリックイベントの追加は、厳密には上書き。 例えば、以下のサンプルコード1では、ボタン押下後はpushButton1メソッドは実行されず、pushButton2メソッドのみ実行される。 サンプルコード1 const button = document.getElementById('button'); button.setAttribute('onclick', 'pushButton1()'); button.setAttribute('onclick', 'pushButton2()'); function pushButton1() { alert('クリックされました -1-'); } function pushButton2() { alert('クリックされました -2-'); } これはsetAtrribute を onclickに変えても同様の動作をする(サンプルコード2)。 サンプルコード2 const button = document.getElementById('button'); button.onclick = pushButton1; button.onclick = pushButton2; function pushButton1() { alert('クリックされました -1-'); } function pushButton2() { alert('クリックされました -2-'); } これらに対してaddEventListenerではメソッドが追加され、イベント時には両方実行される(サンプルコード3・画像1)。 サンプルコード3 const button = document.getElementById('button'); button.addEventListener('click', pushButton1); button.addEventListener('click', pushButton2); function pushButton1() { alert('クリックされました -1-'); } function pushButton2() { alert('クリックされました -2-'); } 画像1 また、サンプルコード4のように書くと、ページ読み込み後のonclick属性にはpushButton1メソッドが入っているにも関わらず(ページ読み込み後html)、ボタン押下時に実行されるのはpushButton2メソッドである(画像2)。 サンプルコード4 const button = document.getElementById('button'); button.setAttribute('onclick', 'pushButton1()'); button.onclick = pushButton2; function pushButton1() { alert('クリックされました -1-'); } function pushButton2() { alert('クリックされました -2-'); } ページ読み込み後html <button id="button" onclick="pushButton1()">ボタン</button> 画像2 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

与えられた2つの数値を反転させて足し算する

与えられた2つの数字を反転させて足し算する 例135と876の場合531+678を実行する const num1 = "136"; const num2 = "295"; // 文字列を配列にする const array1=Array.from(num1); const array2=Array.from(num2); //配列を反転させる const arrayRev1=array1.reverse(); const arrayRev2=array2.reverse(); //配列を文字、数値の順に戻す const rev1=Number(arrayRev1.join("")); const rev2=Number(arrayRev2.join("")); //求める結果の出力 console.log(rev1+rev2);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LineBotのUIを整えて完成~テレ〇限定・今日のドラマ再放送は何やるの?LineBotを作ろうと思う

LineBotの作り方を教わったので、「14時くらいから17時までの「テレ朝 ドラマ再放送ゴールデンタイム」の番組タイトルを教えてくれるLineBotを作ってみる!」にチャレンジしています。今回は前回からの(LineBotに組み込む)の続きであり、完結編です。 LineBotとして必要な機能は準備できたので、今回は操作性や見た目をなどを整えます。 Lineのインターフェースを設定する このBotに期待しているのは「当日」のゴールデンタイムの番組一覧を教えてほしいだけなので、1アクションで動作してくれるのがシンプルで望ましいです。 そこで、Lineの画面にボタンを設置し、それを押したら番組情報を返してくれるようにします。 「リッチメニュー」と呼ばれるもので、下のようなボタンです。 作り方はとても簡単でLineのオフィシャルアカウントマネージャーで設定します。 公式ページに設定の仕方が出ています。簡単に設定できるので公式ページの説明でも十分作成できます。 Lineのアプリを作る際には、「LINE Developers」と「LINE OfficialAccountManager」の両方でいろいろ設定が必要です。ちょっと迷うところかもです。 今回は、ボタンを押下したら、「今日は、何を放送するのかな?」とメッセージを送信するように設定しました。フォームに設定するだけで簡単に作成できました。 Botの機能をレベルアップさせる 番組表を返すだけだとちょっとつまらないので、日の入り時刻を取得するAPIを使って一層便利なBotにします(笑) 具体的には、保育園のお迎え(17時)まで、ドラマを観ていられるか?をアドバイスしてくれる機能!!! うちは、17時には保育園にお迎えに行かないといけませんが、冬場は17時より前に暗くなってしまいます。お迎えは暗くなる前に行きたいところですので、その情報を教えてもらいます。つまりは、17時までドラマを観ていられませんよ!を教えてくれるわけです。便利便利(笑)。 必要に応じて録画とか対策を講じることができます。便利便利(笑) 日の出・日の入りWEBAPIを利用する 日の入り時刻が必要なので、WEBAPIを利用して取得します。 今回は、Sunset and sunrise times APIを利用しました。 hinoiri.js const hinoiriFunction = async (event) => { let pushText = ''; // axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする) const res = await axios.get('https://api.sunrise-sunset.org/json?lat=34.6959484&lng=135.4927352'); //経度緯度を必要に応じて修正 // 取得できるのはUTCなので日本時間(+9時間)になおす const utc_time = res.data.results.sunset; // '時', '分', '秒 PM' に分割する const tm_split = utc_time.split(':'); // '時' を9時間進める const jp_hour = Number(tm_split[0]) + 9 ; const time_string = `${jp_hour}時${tm_split[1]}分`; if(jp_hour <= 17 ){ pushText = `今日の日の入りは${time_string}です。最後まで視聴すると、保育園のお迎えに差支えますよ!`; }else{ pushText = `今日の日の入りは${time_string}です。最後まで視聴していても保育園のお迎えに差支えはありません!`; } //非同期がうまくいかないので、とりあえず2秒待つ// const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); await _sleep(2000); //非同期がうまくいかないので、とりあえず2秒待った あとでちゃんと勉強しよう// // 「プッシュ」で後からユーザーに通知します return client.pushMessage(event.source.userId, { type: 'text', text: pushText, }); お迎え時刻の17時を基準に判定して、メッセージを出しわけます。 相変わらずウェイト処理を入れています・・・ 完成! ついに「テレ〇限定・今日のドラマ再放送は何やるの?LineBot」が完成しました! 動作イメージ↓ 今日は祝日(月)なので、ゴールデンタイムあり!科捜研の女をやるようだ。やったね!科捜研大好き。 これは絶対便利!(笑) まだプロトタイプであり、ローカルPCで稼働している状態です。 コードも直して(非同期のところとか)、機能のレベルアップとか(「100の資格を持つ女」が入っていたら、おめでとうメッセージを出す機能の追加とか)したうえで、herokuなどのサーバで稼働させたいなぁと思います。 最後に このような実践的な(?)アプリが、ほんの数時間で作れてしまいました。 コードとして問題がありますが、プロトタイプとしては十分と思います。 まったくすごい世の中になったものです。引き続きいろいろプロトアウトしてみたいなと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【完成!!】LineBotのUIを整える~テレ〇限定・今日のドラマ再放送は何やるの?LineBotを作ろうと思う

LineBotの作り方を教わったので、「14時くらいから17時までの「テレ朝 ドラマ再放送ゴールデンタイム」の番組タイトルを教えてくれるLineBotを作ってみる!」にチャレンジしています。今回は前回からの(LineBotに組み込む)の続きであり、完結編です。 LineBotとして必要な機能は準備できたので、今回は操作性や見た目をなどを整えます。 Lineのインターフェースを設定する このBotに期待しているのは「当日」のゴールデンタイムの番組一覧を教えてほしいだけなので、1アクションで動作してくれるのがシンプルで望ましいです。 そこで、Lineの画面にボタンを設置し、それを押したら番組情報を返してくれるようにします。 「リッチメニュー」と呼ばれるもので、下のようなボタンです。 作り方はとても簡単でLineのオフィシャルアカウントマネージャーで設定します。 公式ページに設定の仕方が出ています。簡単に設定できるので公式ページの説明でも十分作成できます。 Lineのアプリを作る際には、「LINE Developers」と「LINE OfficialAccountManager」の両方でいろいろ設定が必要です。ちょっと迷うところかもです。 今回は、ボタンを押下したら、「今日は、何を放送するのかな?」とメッセージを送信するように設定しました。フォームに設定するだけで簡単に作成できました。 Botの機能をレベルアップさせる 番組表を返すだけだとちょっとつまらないので、日の入り時刻を取得するAPIを使って一層便利なBotにします(笑) 具体的には、保育園のお迎え(17時)まで、ドラマを観ていられるか?をアドバイスしてくれる機能!!! うちは、17時には保育園にお迎えに行かないといけませんが、冬場は17時より前に暗くなってしまいます。お迎えは暗くなる前に行きたいところですので、その情報を教えてもらいます。つまりは、17時までドラマを観ていられませんよ!を教えてくれるわけです。便利便利(笑)。 必要に応じて録画とか対策を講じることができます。便利便利(笑) 日の出・日の入りWEBAPIを利用する 日の入り時刻が必要なので、WEBAPIを利用して取得します。 今回は、Sunset and sunrise times APIを利用しました。 hinoiri.js const hinoiriFunction = async (event) => { let pushText = ''; // axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする) const res = await axios.get('https://api.sunrise-sunset.org/json?lat=34.6959484&lng=135.4927352'); //経度緯度を必要に応じて修正 // 取得できるのはUTCなので日本時間(+9時間)になおす const utc_time = res.data.results.sunset; // '時', '分', '秒 PM' に分割する const tm_split = utc_time.split(':'); // '時' を9時間進める const jp_hour = Number(tm_split[0]) + 9 ; const time_string = `${jp_hour}時${tm_split[1]}分`; if(jp_hour <= 17 ){ pushText = `今日の日の入りは${time_string}です。最後まで視聴すると、保育園のお迎えに差支えますよ!`; }else{ pushText = `今日の日の入りは${time_string}です。最後まで視聴していても保育園のお迎えに差支えはありません!`; } //非同期がうまくいかないので、とりあえず2秒待つ// const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); await _sleep(2000); //非同期がうまくいかないので、とりあえず2秒待った あとでちゃんと勉強しよう// // 「プッシュ」で後からユーザーに通知します return client.pushMessage(event.source.userId, { type: 'text', text: pushText, }); お迎え時刻の17時を基準に判定して、メッセージを出しわけます。 相変わらずウェイト処理を入れています・・・ 完成! ついに「テレ〇限定・今日のドラマ再放送は何やるの?LineBot」が完成しました! 動作イメージ↓ 今日は祝日(月)なので、ゴールデンタイムあり!科捜研の女をやるようだ。やったね!科捜研大好き。 これは絶対便利!(笑) まだプロトタイプであり、ローカルPCで稼働している状態です。 コードも直して(非同期のところとか)、機能のレベルアップとか(「100の資格を持つ女」が入っていたら、おめでとうメッセージを出す機能の追加とか)したうえで、herokuなどのサーバで稼働させたいなぁと思います。 最後に このような実践的な(?)アプリが、ほんの数時間で作れてしまいました。 コードとして問題がありますが、プロトタイプとしては十分と思います。 まったくすごい世の中になったものです。引き続きいろいろプロトアウトしてみたいなと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript オブジェクトの生成

javascriptのオブジェクトの生成方法など なんでJSってこんなやっこいんだろ・・・ 最初はみんな同じようなものかと思ったんだけどね! sm1={}; sm2=new Object(sm1); sm3=new Object(); sm3.prototype=sm1; sm4=Object.create(sm1); sm5=function(){} sm6=new sm5(); sm7=new Object(sm5()); sm8=new Object(new sm5()); sm9=new Object(); sm9.prototype=new sm5(); sm0=Object.create(new sm5()); console.log(Object.getPrototypeOf(sm1)); // {constructor: ƒ, __defineGetter__:... console.log(Object.getPrototypeOf(sm2)); // {constructor: ƒ, __defineGetter__:... console.log(Object.getPrototypeOf(sm3)); // {constructor: ƒ, __defineGetter__:... console.log(Object.getPrototypeOf(sm4)); // {} console.log(Object.getPrototypeOf(sm5)); // ƒ () { [native code] } console.log(Object.getPrototypeOf(sm6)); // {constructor: ƒ} console.log(Object.getPrototypeOf(sm7)); // {constructor: ƒ} console.log(Object.getPrototypeOf(sm8)); // {constructor: ƒ, __defineGetter__:... console.log(Object.getPrototypeOf(sm9)); // sm5 {} console.log(sm1); // {} \ __proto__: \ constructor:f Object() console.log(sm2); // {} \ __proto__: \ constructor:f Object() console.log(sm3); // {prototype: {…}} \ prototype \ __proto__ \ constructor:f Object() console.log(sm4); // {} \ __proto__ \ __proto__ \ constructor:f Object() console.log(sm5); // f(){} console.log(sm6); // sm5{} \ __proto__ \ constructor:f() || constructor:f Object() console.log(sm7); // {} \ __proto__ \ constructor:f Object() console.log(sm8); // {prototype: sm5} \ prototype:sm5() || constructor:f() console.log(sm9); // {} \ __proto__ \ constructor:f Object() console.log(sm0); // sm5{} \ __proto__ \ sm5 \ __proto__ \ constructor:f() console.log(sm1===sm2); // true console.log(sm1===sm3); // false console.log(sm1===sm4); // false console.log(sm2===sm3); // false console.log(sm2===sm4); // false console.log(sm3===sm4); // false console.log(sm5===sm6); // false console.log(sm5===sm7); // false console.log(sm5===sm8); // false console.log(sm5===sm9); // false console.log(sm5===sm0); // false console.log(sm6===sm7); // false console.log(sm6===sm8); // false console.log(sm6===sm9); // false console.log(sm6===sm0); // false console.log(sm7===sm8); // false console.log(sm7===sm9); // false console.log(sm7===sm0); // false console.log(sm8===sm9); // false console.log(sm8===sm0); // false console.log(sm9===sm0); // false
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript appendChild 親要素に子要素を追加する

要素を追加する 以下の要素に子要素を追加する。 <div id="parent">親要素です</div> 1. 親要素のオブジェクトを取得する。 const parent = document.getElementById('parent'); 2. 子要素のオブジェクトを作成する。 const child = document.createElement('div'); 3. 親要素のオブジェクトのappendChildメソッドに、子要素のオブジェクトを渡す。 parent.appendChild(child); 子要素の追加される場所 子要素は親要素の末尾に追加される。例えばfor文で続けて子要素を追加してみると、以下のような結果になる。 <div id="parent">親要素です</div> const parent = document.getElementById('parent'); for (let i = 0; i < 5; i++) { const child = document.createElement('div'); child.textContent = String(i) + '番目の子要素です' parent.appendChild(child); } 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsが流行っているらしいので使用してみた件

Nuxt.jsが流行っているらしいので使用してみた件 最近でもないのかな?JS由来のフレームワークやらライブラリやらがフロントエンドの主流になってきてるらしいですね。 なので今回、自分自身学習のアウトプットも兼ねてQiitaで情報発信していこうと思います。 不慣れなところもあるとは思いますが、何卒よろしくお願いします。 そもそもNuxt.jsってなんすか。 vue.jsの機能をふんだんに盛り込んだフレームワークという認識でいいと思います。 (SEO対策に強いとかSSRとかいろいろあるけど詳しくは公式ドキュメントを見てね) Nuxt.js公式サイト 実際に動かしてみよう。 Nuxt.jsで開発を進めていくにあたってNode.js環境が必須なので、インストールがまだの方はこちらの記事を参考にされてみてください。 本当の初心者のためのNode.js超入門 ~環境構築編~ インストールが終わったら、下記のコマンドをお手元のCLI(Mac:コンソール, Win:コマンドプロンプト)にて実行してみましょう。 Iterm2 npx create-nuxt-app <namespace> //namespaceは任意の文字 対話形式でいろいろ聞かれます。 プロジェクト名 使用する言語(TSは言語認識か微妙なところ)JS or TS Yarn or npm(高速なyarnが推奨!どうしてもnpmがいい人はそれでも問題はないです。) UIフレームワーク(個人的にはnoneでおk。後々でも追加はできます。) Axios(http通信)かPWA(モバイルapp)かCMS(WordPressなどをいじりたい人)か。Webappを作るならaxios推奨 Lint tool(コードを綺麗に整形してくれる便利なやつ。ESlintで問題ない。) Testing frameworkの選択 無難にjestにしましょう。 SSRかSPAか。個人的にはSSRがオヌヌメです。 Serverかstaticか。これはserverで問題ないです。staticを作りたくなったらそれ用のコマンドがあります。 あとの項目はEnter連打で大丈夫です。 Server Side Rendering(SSR)のメリット SEO対策に効果的! ページの表示が爆速! OGの設定が容易! Server Side Rendering(SSR)のデメリット サーバーへのデプロイがやや大変。(人によっては致命的) Single Page Application(SPA)のメリット 実装が容易 サーバーの準備が比較的簡単 ページ遷移が爆速 Single Page Application(SPA)のデメリット 初期表示が遅い。。。 OGの設定が詳細にできない。 などがありますので、これらを踏まえた上で選択してみてください。 ここまでくればやや時間を要しながら、appの作成が完了したと思います。 iTerm2 cd <namespace> //自分のappの名前 でディレクトリに入り、 iTerm2 yarn dev //npmの人は npm run dev で実行します。(正式には開発モードと言ってローカルで変更した値を即時にビルドして実行してくれる便利なやつ。) デフォルトではポート3000番が開かれてますのでwebブラウザからlocalhost:3000にアクセスしてみましょう。 しっかり表示されてますね。ひとまず安心。 作成したディレクトリに入ると様々なフォルダが作成されていると思います。 何が何だかわからなくて挫折してしまいそうになりますが、グッと堪えてざっくりと概要を理解していきましょう!! ディレクトリの紹介 .nuxt 自分たちが書いたコードをえっちらおっちら実行可能なコードに直してくれているところ。 assets 今後cssなどを入れるためのところ components vue.jsは基本的にコンポーネント(部品)で管理していきます。その部品を記述するところです。コンポーネント指向がいまいちわからないよ。という方向けに下に参考文献貼っておきます。 layouts ページ全体の共通部分をここに記述します。(eg. header footer) middleware レンダリングされる前に実行したい関数の置き場所(認証されてないユーザーへのlogin画面へのリダイレクトなど。) node_modules 先人たちのありがたい知恵が詰まった場所。yarn add xxxとかするとここに入るよ。 pages これが本当に便利。この中に新しくファイルを作ると、そこに勝手にパスを通してくれる。 plugins 全体を通して使用したい関数などを記述する。 static faviconや画像などをここに置いておく。 store アプリケーションを通してのデータの保持。login情報などに主に使用される。 test テストに関する記述がある。 参考文献: Vuejsのちょっと便利なコンポーネント機能 【Nuxt.js】 middleware is 何? Nuxt.jsのpluginsにaxiosの共通部品を実装する とまあこんな感じでゆるっと理解しておけば、いずれ役に立つかと思います。 こんな感じでどしどし開発を進めてみてください。 これから機能ごとに記事をいくつかアップしていこうと考えてます。 もしよければそちらも参考になさってください。 ご視聴ありがとうございました(_ _)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  switch文  私初心者なので 復習

if文以外の条件分岐の方法 switch switch(条件の値・変数や定数) { }セミコロン(;)不要 const color = "黒"; switch(color){ 定数color値に応じて処理を分岐するんだって } さらに caseってのを追加すると処理を分けてくれるよ switch(条件の値) { case 値1:    「条件の値」が「値1」と等しい時の処理    break; } const color = "黒"; switch(color){ case"黒"; console.log("ストップ! ");//定数colorの値が"黒"の時に実行される break; } さらにさらに!switch分では分岐の数だけcaseを追加。 switch(条件の値){ case 値1:    「条件の値」が「値1」と等しい時の処理    break; case 値2:    「条件の値」が「値2」と等しい時の処理    break; } 分岐の数だけcaseを追加する const color = "黒"; switch(color){ case"黒"; console.log("ストップ! ");//定数colorの値が"黒"の時に実行される break; case"赤"; console.log("要注意 ");//定数colorの値が"赤"の時に実行される break; } switch文には さっきから出てきているbreakが必要! breakはswitch文を終了する命令! breakがないと、caseの処理を行なった後、次のcaseの処理もしちゃうので必ずbreakを書くこと。 switch + case + break だね! const color = "黒"; switch(color){ case"黒"; console.log("ストップ! ");//定数colorの値が"黒"の時に実行される //break; ココがなかったら① case"赤"; console.log("要注意 ");//定数colorの値が"赤"の時に実行される break; } //①がなかったら コンソールの表示には  ストップ!   と  要注意が出てしまうよ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.NET Core WebAppにおけるajax通信のメモ

概要 .NET Core WebAppにおいて、ajax通信をする際のクライアントサイド・サーバサイドのお作法を時々忘れてしまうので、 世の中には同じ方がおられるかもしれない、ということで忘備録としてまとめておきます。 クライアントサイド ・URLについて 「/Hoge/」については、C#プロジェクトの「Pages」フォルダ直下のフォルダ名を指定します。 「/Index/」は上記フォルダ直下のファイル名を指定します。 例: 「/Pages/Hoge/Index.cshtml.cs」ファイルにリクエストする場合、リクエストURLは「/Hoge/Index/」と指定します。 その後続けて「?handler=」(決り文句)を記述し、 「GetList」はサーバサイドのメソッド名を指定します。 パラメーターを追加する場合は、「&{キー}={値}」と連ねて記述できます。 POSTの場合は、typeに「POST」を指定し、 「data: JSON.stringify({JSON})」プロパティを追加するだけの違いです。 $.ajax({ type: 'GET', url: '/Hoge/Index/?handler=GetList&param1=1&param2=2', dataType: 'JSON', contentType: 'application/json; charset=utf-8', beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, processData: true, cache: false, }).done(function (data) { // OK時の処理 }).fail(function (data) { // NG時の処理 }); サーバサイド ・メソッド名のプレフィックスに「OnGet」を書く必要があります。 ただし、クライアントサイドからリクエストする場合は、「OnGet」は省略します。 例: メソッド名が「OnGetGetList」の場合、リクエスト先URLは「GetList」となります。 ・返り値の型はIActionResultになります。 public IActionResult OnGetGetList(int param1, int param2) { try { } catch (Exception e) { } return new JsonResult(json); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS~要素の書き換え~

概要 DOM取得した後の、要素の中身操作についての記事です。 JSでは、イベント発生(ユーザーがクリックしたとき)などに処理が始まります。 今回はクリックイベントから要素の書き換えを行う操作についの記事です。 実装内容は以下のようになります。 1,クリックイベント 2,要素の書き換え 3,classの追加 イベント Webページでは、ユーザーが操作したときにイベントが発生します。また、イベント発生時の処理をJSで登録することができます。 またそれらのユーザーからのイベントを関数で登録します。 main.js window.addEventListener(イベント名,コールバック関数) 要素の取得 HTML クリックイベントはボタンにしました。 クリックイベント発生後に、ul要素の中身に色がつくように実装します。 index.html <button>ボタン</button> <ul id="task"> <li>リスト</li> <li>リスト</li> <li>リスト</li> </ul> JS 最初に、クリックイベントに登録するbuttonというタグ名を取得します。 定数button(わかりやすいように)にquerySelectorでタグ名を代入。 console.logで取得しているか確認しました。 次に、取得したbuttonをクリックイベントに登録します。 クリックイベント時に、li要素を書き換えたいのでli要素を取得します。 ボタンをクリックして、li要素が取得されているか確認してみてください。 main.js const button = document.querySelector('button'); console.log(button); button.addEventListener('click',() =>{ const li = document.querySelectorAll('li'); console.log(li); }); 書き換え ボタンを押したときにli要素が書き換わるように実装しました. forEachで繰り返し、innerHTMLで書き換えました。 index.js button.addEventListener('click',() =>{ const li = document.querySelectorAll('li'); console.log(li); // li[2].innerHTML = 'abcd'; li.forEach(list =>{ list.textContent = 'OK!!'; }); }); 書き換えプロパティにはいくつか種類があるにで、使用目的で使い分ける必要があります。 class属性の操作 1,classList.add(); 次に、class属性の操作していきます。 クリックしたときに、文字色が赤になるように実装していきます。 main.js const button = document.querySelector('button'); console.log(button); button.addEventListener('click',() =>{ const li = document.querySelectorAll('li'); console.log(li); // li[2].classList.add('list'); li.forEach(list =>{ list.textContent = 'OK!!'; list.classList.add('list');//class属性 }); }); クリックしたときにJS側からクラス属性を付けます。なお、CSS側でスタイルを設定します。 style.css .list { color: red; } 2,classList.toggle クラス属性の付け外しを行います。 index.html <li class="lis">リスト</li> <li class="lis">リスト</li> <li class="lis">リスト</li> style.css .lis { color: yellow; } main.js list.classList.toggle('list'); 先程のclassList.addを書き換えると、listクラスのつけ外しをすることができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  && ||  私初心者なので 復習

&& katu かつ??????????????????????????????? 複数の条件が全てtrueならtrueになる??????? xが30の時 x > 10 && x < 40 ・・・true ↑true ↑true xが6の時 x > 10 && x < 40 ・・・false ↑false ↑true ||または・・・????????????????????? 条件1または条件2 条件1||条件2 この場合、複数の条件のうち1つでもtrueならtrueになる xが6の時 x < 10 || x > 40 ・・・true ↑true ↑false xが30の時 x < 10 || x > 40 ・・・false ↑false ↑false 具体的にもっと見てみよう console number = 41; if(number >= 10 && number < 100) { //↑true かつ ↑true 両方trueだから・・・おっけ!trueになるね console.log("numberは2桁です"); } //コンソール表示には numberは2桁です  と出るよ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む