20201024のJavaScriptに関する記事は23件です。

即時に更新されるチャット機能(Action Cableの実装)

即時に更新されるチャットアプリ

  • Action Cableを用いた、リアルタイムチャットアプリを作成する

まとめてコードずらりします⬇︎

ターミナル
% cd projects
% rails _6.0.0_ new mini_talk_app -d mysql
% cd mini_talk_app
% rails db:create
ターミナル
% rails g controller messages new
% rails g model message text:text
% rails db:migrate
app/config/routes.rb
Rails.application.routes.draw do
  root 'messages#new'
  resources :messages, only: [:create]
end
app/controllers/messages_controller.rb
class MessagesController < ApplicationController
  def new
    @messages = Message.all
    @message = Message.new
  end

  def create
    @message = Message.new(text: params[:message][:text])
  end
end
app/views/messages/new.html.erb
<h3>mini_talk_app</h3>
<%= form_with model: @message do |f| %>
  <%= f.text_field :text %>
  <%= f.submit '送信' %>
<% end %>
<div id='messages'>
  <% @messages.reverse_each do |message| %>
    <p><%= message.text %></p>
  <% end %>
</div>

この時点で下記のようになっているはず

d6806db02ad04b485928bbd124c73f1a.png

Action Cableの実装(先ほどの続き)

ターミナル
% rails g channel message
app/channel/message_channel.rb
class MessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "message_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end
app/controller/messages_controller.rb
class MessagesController < ApplicationController
  def new
    @messages = Message.all
    @message = Message.new
  end

  def create
    @message = Message.new(text: params[:message][:text])
    if @message.save
      ActionCable.server.broadcast 'message_channel', content: @message
    end
  end
end
app/javascript/channels/message_channel.js
import consumer from "./consumer"

consumer.subscriptions.create("MessageChannel", {
  connected() {
    // Called when the subscription is ready for use on the server
  },

  disconnected() {
    // Called when the subscription has been terminated by the server
  },

  received(data) {
    const html = `<p>${data.content.text}</p>`;
    const messages = document.getElementById('messages');
    const newMessage = document.getElementById('message_text');
    messages.insertAdjacentHTML('afterbegin', html);
    newMessage.value='';
  }
});

現場からは以上です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[メモ] JavaScript 参照

変数aを定義し、1を入れた時
それぞれメモリ空間上に配置される

def.js
let a = 1;

aは1への参照(住所みたいなイメージ)を保持している

スクリーンショット 2020-10-23 16.00.48.png

変数b変数aをコピーした時

def.js
let a = 1;
let b = a;

値の1がコピーされ、その参照を持つ変数bが作られる

スクリーンショット 2020-10-24 12.49.35.png

それぞれ別の参照先なので、変数bに再代入しても、変数aは影響を受けない
参照先が張り替えられるだけ

def.js
let a = 1;
let b = a;
b = 2;

console.log(a,b); // 1 2

スクリーンショット 2020-10-24 13.24.29.png

オブジェクト

def.js
let user = {
    name: '山田'
};

上記のようなオブジェクトが定義されている時

変数userは「オブジェクトへの参照」に対して参照をもつ
オブジェクトのプロパティはそれぞれの値への参照をもちます
スクリーンショット 2020-10-24 13.48.11.png

このオブジェクトをコピーします

def.js
let user = {
    name: '山田'
};

let secondUser = user;

ここでコピーされるものは「オブジェクトへの参照」です
「オブジェクトへの参照」への参照を変数secondUserはもちます

スクリーンショット 2020-10-24 13.48.04.png

なので、オブジェクトの参照はそのまま残っているので、書き換えると両方変わります

def.js
let user = {
    name: '山田'
};

let secondUser = user;

secondUser.name = '田中';

console.log(user.name, secondUser.name); // 田中 田中

See the Pen Object Reference by natusme (@natsume0718) on CodePen.

これは、メソッドの引数の時も同様の挙動となる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScripの復習

基本を見直しました。

if文をswich文に、書き直して見ました。

if文のコード

var firstName ="yourname";
var age = 18;

if(age < 15){
    console.log(firstName + 'is a junior high school student');
} else if(age >=15 && age < 18 {
    console.log(firstName + 'is a high school student');
} else if(age >=18 && age < 20) {
  console.log(firstName + 'is a university student');  
} else {
    console.log(firstName + 'is a salary man');
} 
}

これをswich文に書き直すと

swich文

var firstName = "yourname";
age = 24;
switch (true){
    case age < 13: 
        console.log(firstName + 'is a junior high school student.');
        break;
    case age >=13 && age < 18: 
        console.log(firstName + 'is a high school student.');
        break;
    case age >=18 && age < 22: 
        console.log(firstName + 'is a university student.');
        break;
    default:
        console.log(firstName +'is a salaryman.');     
}  

出たエラーメッセージ

Uncaught SyntaxError: Unexpected end of input

自分で試したこと

ageの指定範囲を変えましたが、エラーがでます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ハッカソン参加(カラオケハック)自分用メモ

ハッカソン参加の自分用メモ

ニューノーマル時代のカラオケをハックせよ Sponsored by JOYSOUND #protoout
ニューノーマル時代だからこその「新しいカラオケ」の楽しみ方を生み出すハッカソンです。カラオケそのものの楽しみ方から、友達への誘い方、終了後の余韻まで、カラオケにまつわるあらゆるシーンをハックし、「ニューノーマル時代のカラオケ」のあり方を提案しましょう!

作る概要決め

・カラオケのガヤ(合いの手)を入れるボット?
・LINEBOTで入力 → 中継サーバ → Webページで表示(ガヤ再生)
 ※LINEBOTだとコネクションを常に張るのは難しいとのことなので、中継サーバを利用。
・音楽は決め打ち。 → 大塚愛/さくらんぼ。

※アドバイス
データ受け渡し部分を先に決めるのが良いと思うが、時間的に厳しいハッカソンなので、連携ができなくても問題ない。LINEBOT、Webページはユーザが使う部分なので、使い勝手を意識したら良い。

Webページ作成
youtube、Webページ、MP4スクリプト、オーディオタグ で調べると良いかも。

役立ちそうなリンク

●Webアプリの作り方(思い出し用)
 ・Codepenサンプル1(ToDo・CSSなし)
 ・Codepenサンプル2(ToDo・Bootstrap)
 ・Codepenサンプル3(axios・COVID-19App)

●音の再生はどうやるの?受け取った音声ファイルを自動再生?
 ・vue.jsで複数のvideoタグを扱う - Qiita
 ・ChromeとSafariでaudioタグを自動再生するための対策
 ・Vue on CodePen - Vue Patterns & Templates (player検索)

●音楽再生のよさそうなAPI(howler.js)
 ・howler.js - Doc
 ・[HTML5] 音声ファイルをJSで再生/停止する – howler.js編

●音楽再生のよさそうなAPI(Youtube Player API)
 ・自宅で夏の散歩ができる「夏休み君」をYoutube Player APIで作ってみた - Qiita

●音源サンプル
 ・フリー効果音素材・無料効果音 - 無料効果音で遊ぼう!
  → 「DL」のリンクをコピーすればmp3のURL取得できる。

●データの受け取り
 ・PubNubアカウント作成方法
 ・PubNub
  → 中継サーバの構築も不要で、リアルタイムに受け取れる。(恐らく簡単かも?)
  ※下のコードは単純に受けたメッセージを表示するサンプル

HTML
<div>
  <h1>GAYA Play</h1>
  <h1 id="gaya"></h1>
</div>
JS
var pubnub = new PubNub({
  subscribeKey: "myPublishKey",
  publishKey: "mySubscribeKey",
})

pubnub.addListener({
    status: function(statusEvent) {
      if (statusEvent.category === "PNConnectedCategory") {
        console.log('connect')
      }
    },
    message: function(message) {
      console.log(message)
      gaya.innerHTML = message.message
    },
})

pubnub.subscribe({
  channels: ['gaya'],
})
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

innerHTML とtextContentの違い

textContentが出てきた時に「innerHTMLとは何が違うのだろう?」と疑問に思ったため調べたことを記録します。

innerHTML

Element オブジェクトの innerHTML プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりします。

textContent

textContent は Node のプロパティで、ノードおよびその子孫のテキストの内容を表します。

文章だけではよくわからなかったので実際に以下のコードを実行します。

html
<html>
  <body>
    <input type="button" value="innerHTML" onclick="reWrite1()">
    <input type="button" value="textContent" onclick="reWrite2()">
    <p id="p1">ここがかわるよ</p>
    <script>
      function reWrite1(){
        const p1 = document.getElementById('p1')
        p1.innerHTML = "<b>変更しました!</b>"
      }

      function reWrite2(){
        const p1 = document.getElementById('p1')
        p1.textContent = "<b>変更しました!</b>"
      }

    </script>
  </body>
</html>

結果
・innerHTMLボタンをクリック
e2d5b4c22abf9fb950bbfe018c736492.png

・textContentボタンをクリック
651cb8d0da6ab73e06bcddce9f891aa3.png

結論

innerHTMLメソッドではタグはHTMLとして解釈されて表示される。
textContentメソッドではタグは文字として表示される。

参考記事

https://developer.mozilla.org/ja/docs/Web/API/Element/innerHTML
https://developer.mozilla.org/ja/docs/Web/API/Node/textContent
https://itsakura.com/js-textcontent-innerhtml

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Progate Javascript 変数・定数

変数とは

ここからは変数
変数は、データ(値)の入れ物(箱)です。箱についている名前が「変数名」であり、箱の実際の値が入っています。

変数
・変数名(箱)
・値(入れ物)

変数の定義

変数は「let 変数名=値」として定義します。プログラミングの
「=」は「等しい」という意味ではなく「左右を左辺に代入」という意味という意味
「let」は「これから変数を定義」

script.js
let name="john";

変数宣言 変数名="代入する値";

・変数宣言 let
・変数 name
・= 代入
・値 "john"

変数の使い方

「"john"」という値が代入された変数nameを
console.log("john")出力すると、
「"john"」という値が出力されます。

script1.js
let name="john";
*console.log(name);

置き換えのイメージ

script2.js
let name="john";
*console.log("john");

*script1「console.log(name);」
変数nameが値("john")に置き換わる
*script2「console.log("john")」

john
が出力される

変数と文字列

これまで見てきた様に、変数のクォーテーションで囲みません。
「console.log("name");」のように変数名のクォーテーションを囲むと
nameが変数ではなく「文字列」として認識され、「name」とそのまま出力されてしまうので注意

script.js
let name="john"
console.log(name);
console.log("name")
john
name そのまま出力される

変数の特徴

変数は、これまでに学習してきた「文字列」や「数値」とまったく同じように
扱えます。
代入される値が、文字列の場合は他の文字列と連結することができ、
数値の場合は計算に用いることができる

script.js
let name="鈴木";
console.log(name + "さん");

let number=11;
console.log(number + 5);

鈴木さん

16

なぜ変数を使うのか

実際のプログラムの中には多くの値を登場します。
プログラムを書くときは、それらの値を間違いのないように、そして値の変更に対応しやすいようにすることが求められます。それを助けるための1つの仕組みが変数

1.同じ値を繰り返し使える
2.変更に対応しやすい
3.値の意味がわかりやすい

変数のメリット

「同じ値を繰り返し使える」「変更に対応しやすい」という具体的に見てみよう。
似たような文章を書くのは何度も面倒ですが、変数を使えば、
同じ値を繰り返し使え、楽にコードを書くことができます。
文章が後になって変更されても、変数を用いていれば、代入する値を
変更するだけで全ての変更に対応できます。

変数を使用しない場合

scirpt.js
console.log("鈴木さん" おはようございます);
console.log("佐藤さん" おはようございます);
console.log("田中さん" おはようございます);

「おはようございます」の部分を
「こんにちは」に変えるなら
おはようの3箇所を全て記入する必要があります。

変数を使用する場合

script.js
let text="おはようございます"
console.log("鈴木さん"+text);
console.log("佐藤さん"+text);
console.log("田中さん"+text);

「おはようございます」の部分を
「こんにちは」に変えるなら
変数に代入する文字列を変更するだけでよi

変数の命名のルール

変数名(変数の名前)は自由に決めることができますが、
できるだけわかりやすい名前をつけるようにしよう

◎良い例
number・・・英単語を用いる
oddNumber・・・2語以上の場合は大文字で区切る

×悪い例
1numebr・・・数字開始(エラーが出る)
bango・・・ローマ字(望ましくない)
番号・・・日本語(望ましくない)

演習

script.js
// 変数lengthを定義してください
let length=5;

// 変数lengthの値を出力してください
console.log(length);

// 変数lengthを用いて、円の面積を出力してください
console.log(length*length*3);

変数の更新

変数は、一度代入した値を変更することもできます。
一度値を代入した変数に、その後再び代入すると、
後に代入した値で変数の中身が上書きされます。
定義する時と違って「let」は必要なく、
変数名=新しい値」と書けば値が変更されます。

script.js
let name="john"
console.log(name);
name="Kate";

!更新するときletはつけない!

console.log(name);
John
Kate

変数の更新イメージ

プログラムは上から順に実行される

script.js
let number=7;
//numberの値は「7」

number=9;
//numberの値は「9」

number=10;
//numberの値「10」

演習

let name = "にんじゃわんこ";
console.log(name);

// 変数nameの値を"とりずきん"に更新してください
name="とりずきん";

// 変数nameの値を出力してください
console.log(name);

変数自身を更新する

既に定義している変数numberの値に3を足したい、というときは
どのようにすれば良いか
numberに3足して、再びnumberに代入することで実現できる
「=」の右側のnumberは値に置き換わり、計算された結果が、
numberに代入されます。

script.js
let number=2;
console.log(number);

number=number+3;
console.log(number);
2
5

変数自身に代入するイメージ

変数を変数自身を使って更新する

script.js
let number=2;
//numberの値は「2」

number = number + 3;
//numberの値は「5」

省略した書き方

「number = number +10」といった書き方には、省略した書き方もあります

script.js
基本形
x=x+10  x+=10
x=x-10  x-=10
x=x*10  x*=10
x=x/10  x/=10
x=x%10  x%=10

演習

script.js
let number = 7;
console.log(number);

// 変数numberの値に3を加えてください
number+=3;

console.log(number);

// 変数numberの値を2で割ってください
number/=2;

console.log(number);

定数(const)とは

変数(let)とよく似たものに、定数(const)があります。
定数(const)はletの代わりにconstを用いて定義
変数(let)と定数(const)の違い

script.js
const name="john";
定数の宣言 定数名=代入する値

定数と変数の違い

変数(let)と定数(const)の違い

変数(let)は1度代入した値を更新することができましたが、
定数(const)は値を変更することはできません
定数(const)の値を更新しようとすると、コードを実行した際にエラーが発生してしまう!

<補足>
複数の変数から一つの同じオブジェクトを参照したり、
リストなどの参照型データを使うことで値を変更することは可能です。
変更というより参照という言葉がぴったりですが...
詳しくはコメント欄をチェック!詳しい方が説明してくれています。

script.js
let name="john";
console.log(name); //出力結果:john

name="Kate";
console.log(name); //出力結果:Kate

変数は代入されている値を更新することができる

script.js
const name="john";
cosole.log(name); //出力結果 :john
name ="Kate";

×エラー!
定数(const)は一度代入された値を更新することはできない

console.log(name);

定数を使うメリット

定数のメリットは「後から値を更新できない」
一見不便に感じますが、予期せぬ更新を防ぐことができ、
より安全なコードを書くことができます。これはコードの量が増えるにつれて
徐々にメリットとして感じる

変数の場合
script.js
let name="john";
:
:
console.log(name);
とすると、途中で値が変わっている可能性

定数の場合

script.js
const name="john";
:
:
console.log(name);
とすると定数なので値は"john"から変わらない
script.js
// 定数languageを定義してください
const language="フランス語";

// 定数languageの値を出力してください
console.log(language);

// 定数languageを用いて、「〇〇を話せます」と出力してください
console.log(language + "を話せます");

テンプレートリテラル

定数の連結には今まで「+」記号を用いてきました。
テンプレートリテラル」という連結方法があります。
テンプレートリテラルを用いると、文字列の中に定数(変数)を埋め込むことができます。

shift + @ = `
テンプレートリテラルを囲む際には、バッククォーテンションを使う

+ではなく${name}

scirpt.js
const name="にんじゃわんこ"
console.log(`こんにちは、${name}さん`);
//console.log("こんにちは"+ name + "さん")

こんにちは、にんじゃわんこさん

テンプレートリテラルの書き方

文字列の中で「${定数}」とすることで、文字列の中に定数や変数を含めることができます。
このとき文字列全体をバッククォーテーションで囲む必要があります。
複数の変数や定数を埋め込むことも可能

script.js
const name="にんじゃわんこ";
console.log(`こんにちは、${name}さん`)

script.js
const name="にんじゃわんこ";
const age=14;
console.log(`${name}${age}歳です`);
にんじゃわんこは14歳です

バッククォーテーションの書き方

shift + @ = `

演習

scirpt.js
const name = "にんじゃわんこ";
const age = 14;

// 「ぼくの名前は〇〇です」とコンソールに出力してください
console.log(`ぼくの名前は${name}です`);

// 「今は〇〇歳です」と出力してください
console.log(`今は${age}歳です`);

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Progate JavaScript 文字列と数値

JavaScript(ES6)とは

従来のJSより効率的コードのかける新しい仕様のバージョン
2015(ES6)

プログラムを実行してみよう

「console.log("〇〇")」と書くと〇〇という文字がコンソールに出力されます。

script.js
console.log("Hello World");

演習

scirpt.js
console.log("「ES6 学習コース」へようこそ!");
console.log("にんじゃわんこと一緒にES6を学んでいきましょう。");

console.log()

コードの書き方をより詳しく見ていきましょう。
console.log()は丸括弧()内に入力された文字をコンソールに出力
また「Hello World」の様な文字のことを文字列と呼びます。文字列は、シングルクォーテーションか、(`)ダブルクォーテーションで囲む必要があるので、注意

script.js
console.log('Hello World')
console.log("Hello World")

×

script.js
console.log(Hello World);

セミコロン

文の最後はセミコロン(;)で終わります。セミコロンはなくても正直に動作する場合が多いですが、思わぬ不具合が生じる場合があります

script.js
console.log("Hello World");

コメントアウト

文頭に「//」を書くと、その行はコメントとみなされます。そのため、
プログラムとしては無視され、実行されません。(コメントアウトと言います)
コメントは、どの様な意味のコードであるのか記すメモとして使われます。

script.js
//console.log("Hello World");

//Helloと出力します

console.log("Hello World");

演習

script.js
// 「Hello World」とコンソールに出力してください
console.log("Hello World");

// 「にんじゃわんこ」とコンソールに出力してください
console.log("にんじゃわんこ");

// 以下の行をコメントアウトしてください
//console.log("この行をコメントアウトしてください");

数値と計算

プログラミングでは、数値(数字)を扱うこともできます。
数値は文字数と違いクォーテーション囲みません。
数値は足し算や引き算といった計算もすることができます。
足し算「+」、引き算には「-」の記号を用います。
数値と記号は全て半角で記述する

script.js
console.log(3);

console.log(5+2);

console.log(3-2);

文字列と数値

console.log(5+2);は足し算の結果である7
一方、「5+2」にクォーテーションをつけると、文字列と解釈されそのまま
出力されます。
文字列と数値は明確に違うもの

script.js
console.log(5+2);
console.log("5+2");

script.js
// 5と3を足した値を出力してください
console.log(5+3);

// 20から8を引いた値を出力してください
console.log(20-8);

// "4 + 5" を文字列として出力してください
console.log("4+5");

計算してみよう(2)

掛け算「」、割り算「/」
掛け算は「
」(アスタリスク)、割り算「/」(スラッシュ)という記号を用いて
計算することができます。

script.js
console.log(3*7);
console.log(6/3)

余りの計算「%」

さらに、「%」記号を使うと、割った時の余りを求めることができます。

script.js
console.log(9%2);
1

9割る2は、4余り1

演習

script.js
// 8と4をかけた結果を出力してください
console.log(8*4);

// 24を4で割った結果を出力してください
console.log(24/4);

// 7を2で割った余りを出力してください
console.log(7%2);

文字列の連結

「+」記号を用いると、文字列同士を連結することができます。
「"にんじゃ"+"わんこ"」とすると「"にんじゃわんこ"」という1つの文字列

script.js
console.log("にんじゃ" + "わんこ");
console.log("A" + "B" + "C" );

文字列の数値の違い

ここでも文字列と数値の違いを確認
"3" + "5"は「35」という文字列になる、3+5は「8」
「文字列と数値は別もの」

script.js
console.log("3" + "5");

console.log(3 + 5);

演習

script.js
// 「ひつじ」と「仙人」を連結してコンソールに出力してください
console.log("ひつじ"+"仙人");

// 文字列の「20」と「15」を連結してコンソールに出力してください
console.log("20"+"15");

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Chrome拡張】別タグ開いてLocalStorageの値を取得してみました

タイトルのことを業務で頼まれたので、作ってみました(無駄にVue.jsを使っています)。
指定されたURLを裏で開きまして、ローカルストレージの値を取得しに行きます。

Vue.js-v1.0.28-csp

↓ファイル構成はこんな感じです。

├─LocalStorageGet
│  background.js
│  manifest.json
│  popup.css
│  popup.html
│  popup.js
│  vue.min.js
manifest.json
{
  "name": "LocalStorage Access Sample",
  "description": "LocalStorage Access Sample",
  "version": "0.0.1",
  "manifest_version": 2,
  "permissions": [
    "tabs"
  ],
  "content_scripts": [{
    "matches": ["https://*/*", "http://*/*"],
    "js": ["background.js"]
  }],
  "browser_action": {
    "default_title": "LocalStorage Access Sample",
    "default_popup": "popup.html"
  }
}

表示部分です。
vue.min.jsと独自に作ったpopup.jsを読み込んで、viewという変数を表示させています。

popup.html
<!DOCTYPE html>
<html>
    <head>
        <title>LocalStorage Access Sample</title>
        <link rel="stylesheet" href="popup.css">
    </head>
    <body>
        <div id="app">
            <p>LocalStrage is: {{ view }}</p>
        </div>
        <script src="vue.min.js"></script>
        <script src="popup.js"></script>
    </body>
</html>

popup.jsの中で、https://test.comに非選択状態でアクセスして、タブの表示の完了(chrome.tabs.onUpdated)を待って、対象のページに仕込んだbackground.js(後述)にメッセージを送っています。
その結果をviewに設定しています。
そしてそのあとに閉じます(chrome.tabs.remove)。

popup.js
window.addEventListener('DOMContentLoaded', () => {
    new Vue({
        el: '#app',
        data: {
            view: '',
        },
        created: function() {
            chrome.tabs.create({url: 'https://test.com', selected: false }, (tab) => {
                chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
                    if(tabId === tab.id && changeInfo.status === 'complete'){
                        chrome.tabs.sendMessage(tab.id, { method: 'getItem', key: 'sampleId', }, (response) => {
                            this.localStrageValue = response && response.data;
                            chrome.tabs.remove(tab.id);
                        });
                    }
                });
            });
        }
    });
});

対象ページに仕込むコードはこちら。

background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if(request.method === 'getItem'){
        sendResponse({data: localStorage.getItem(request.key)});
    }
});

作った拡張をChromeに読み込ませて、アイコンをクリックすれば、

キャプチャ.JPG

こんな感じで表示されるはずです(上記画像は適当にランダムな値を設定しております)。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsにVue.jsを導入する

備忘録

今回はrailsで開発中のアプリにVue.jsを導入したので備忘録として記録します。
初めてrailsでVue.jsを使う人の助けになればと思います。
また、初心者のため間違いなどあればご指摘お願いします!
ruby 2.6.5
Rails 6.0.3.3

ステップ1webpackerのインストール

インストール済みの方はスキップして下さい
Gemgile内に記述

gem "webpacker", github: "rails/webpacker”

記述できたらbundle installしましょう。

インストールできたらターミナルで以下を実行

$ bin/rails webpacker:install

これでwebpackerのインストールが完了

ステップ2 Vue.jsのインストール

ターミナルで以下コマンドを入力

$ rails webpacker:install:vue

これでVue.jsに必要なファイルなどが作成されました。

ステップ3 Vue.jsの読み込み

app/views/layouts配下のapplication.html.erbファイルに以下を記述

 <%= javascript_pack_tag "hello_vue" %>

正常に読み込まれると写真のようにviewに表示されます。
https://gyazo.com/57e56686d2113920659f3dc9410f3a15

最後に

以上でrailsでVue.jsを導入する事ができました!
比較的に簡単に導入する事ができるのでよければ使ってみて下さい!
何か間違えなどあればご教授下さい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スクラッチからWebpack+Babel+Vue 3を使う

スクラッチからWebpack+Babel+Vue.jsを使う をVue 3に対応させてみました。

Vue CLI も Rails+Webpacker も使わずに、Vue.js(Single File Component)のバージョン3を試す方法です。スクラッチから作るのが好きな人、WebpackとBabelが吐いたコードを眺めたい人はどうぞ。

準備

てきとうなディレクトリを作り、yarnで必要なモジュールをインストールします。

% mkdir scratch && cd scratch
% yarn add @babel/core @babel/preset-env babel-loader core-js vue@next vue-loader@next @vue/compiler-sfc vue-template-compiler webpack webpack-cli

vue と vue-loader をVue 3のものにするために vue@nextvue-loader@next とします。また、vue-loader を動かすのに @vue/compiler-sfc が必要です。

最終的なディレクトリとファイルの配置は次のようになります。

- dist
  - app.js
  - app.js.map
- node_modules
- src
  - app.js
  - hello.vue
- babel.config.js
- index.html
- package.json
- wbpack.config.js
- yarn.lock

Vueアプリケーション

HTMLと簡単なVueアプリケーションを書きます。Vue 2との違いは、アプリケーションを作成してマウントする部分 createApp(Hello).mount('#app'); だけです。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>てすと</title>
    <script src="dist/app.js"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
src/app.js
import "core-js/stable";
import "regenerator-runtime/runtime";

import { createApp } from 'vue';
import Hello from './hello.vue';

document.addEventListener('DOMContentLoaded', () => {
  createApp(Hello).mount('#app');
});
src/hello.vue
<template>
  <div>
    <h1>{{message}}</h1>
    <p><input v-model="message"></p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: ''
    };
  },
  created() {
    this.message = 'hello';
  }
}
</script>

webpack.config.js

webpack.config.js を書きます。src/app.js が dist/app.js に出力されるようにします。

webpack.config.js
const { VueLoaderPlugin } = require('vue-loader');
const webpack = require('webpack');
const path = require('path');

const env = process.env.NODE_ENV || 'development';

module.exports = {
  entry: './src/app.js',
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'source-map',
  mode: env,
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader'
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new webpack.DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false
    })
  ]
}

1行目は、Vue 2では、

const VueLoaderPlugin = require('vue-loader/lib/plugin');

としていたところをVue 3ではちょっと変えます。

const { VueLoaderPlugin } = require('vue-loader');

plugins: のところで、2つのオプションを指定していますが、これがないと実行時にWarningが出ます(Bundler Build Feature Flags を参照)。

    new webpack.DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false
    })

babel.config.js

IE 11対応にするために、babel.config.js に preset-env の設定を書きます。ここは Vue 2のものから変えていません。

babel.config.js
module.exports = api => {
  api.cache(true);

  return {
    presets: [
      [
        "@babel/preset-env",
        {
          targets: { ie: "11" },
          useBuiltIns: "entry",
          corejs: 3
        }
      ]
    ]
  }
}

コンパイル

package.json に scripts.build を追加すると、yarnコマンドでwebpackを呼び出せます。

package.json
{
  "scripts": {
    "build": "webpack --config=webpack.config.js"
  },
  "dependencies": {
    "@babel/core": "^7.12.3",
    "@babel/preset-env": "^7.12.1",
    "@vue/compiler-sfc": "^3.0.2",
    "babel-loader": "^8.1.0",
    "core-js": "^3.6.5",
    "vue": "^3.0.2",
    "vue-loader": "^16.0.0-beta.8",
    "vue-template-compiler": "^2.6.12",
    "webpack": "^5.2.0",
    "webpack-cli": "^4.1.0"
  }
}

yarn build とすると、webpackが dist/app.js を生成します。

% yarn build

環境変数 NODE_ENV を production にすると、本番環境用に圧縮された dist/app.js ができます。

% NODE_ENV=production yarn build

index.html を ブラウザーで開いてVueアプリケーションが動けば成功です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

toioを使って簡単にゾートロープ(立体アニメーション)を作る方法

サマリ

本記事にはtoioを使って簡単にゾートロープ(立体アニメーション)を作る方法が記載されています。
基本は家にあるものだけで、以下の動画の様な体験ができるので、大変手軽で面白いです。

成果物

きっかけ

私自身はコロナの影響もあり参加を見送ったのですが、2020年10月に開催された、Maker Faire Tokyo 2020にて、パンタグラフさんが出典されていた『パンタグラフのゾートロープ | Zoetrope of PANTOGRAPH』が超絶良かったので、ぜひ自宅でも簡単に再現したいなと思い構想をはじめました。
まずは、パンタグラフさんの作品(すごい)をご覧ください。
IMAGE ALT TEXT HERE
IMAGE ALT TEXT HERE

さて、自宅で再現するにあたり、昨今のご家庭には動画の様なレコードプレーヤーは少ないと思い、よりありふれており手軽な(異論は認める)toioを使って実現してみることにしました。また、toioを使えば、回転速度や回転の向き、複数個の同時回転などレコードプレーヤーでは実現できなかった表現も可能になるのでは、と思い開発に着手しました。
結果的にすべてを満たす簡単便利ツールが出来上がったので、子供向けワークショップとかで使ってもらえるといいなと思っています。

準備

一覧

下記をご用意ください。

  • 工作シート (1枚)
    • A4サイズのコピー用紙や画用紙に原寸で印刷してください。
  • ストロボスコープのサンプルシート (1枚)
    • こちらも、A4サイズの紙に原寸で印刷してください。
  • 不要なCD/DVD (1枚)
  • toio™Core Cube (1個)
  • toio™Core Cube専用プレートか、LEGOの4*4プレート (1枚)
  • キューブ制御用 Windows/Mac PC (1台, Bluetoothが使えること)とブラウザ
    • ブラウザはGoogle Chromeを推奨します。
    • たぶんAndroidでも動きます。残念ながらiOS/iPad OSではAppleのポリシー的に動かせません。
  • アニメーション閲覧用 iPhone, iPad (1台)
    • StroboScopeAppを購入し、インストールしておく必要があります。OSは13以上の方が望ましいようです。
      image.png
  • ハサミ、セロテープ、両面テープなどの文具

最終的な構成

こんな感じで使うことになります。
topology.png

遊びの手順

1. キューブのソフトウェア動作確認

まずは、ソフトウェアでキューブを動かせるかを確認しましょう。

  1. キューブの電源をONにします。
  2. また、事前にWindows PC/ macOS PC上で、BluetoothがONになっていることを確認してください
  3. PCにてGoogle ChromeからStroboscope with toio™Core Cubeにアクセスします。
    image.png
    1. ココでソースコードも見られますヨ
  4. この画面をクリックしてキューブと接続します
    image.png
    1. キューブを選択し『ペア設定』ボタンを押して少し待つと、接続処理が完了しキューブのランプが白く光ります。
  5. スペースキーを一度押すと、背景が黄緑色になり、キューブが回転し始めたらOKです!もう一度スペースキーを押すと回転が止まります。
    1. 上に載せるモノへの影響を極力少なくするために、加減速して目的スピードに達する仕様になっています
  6. さらに細かく調整したい方向けに、最大回転速度と、回転方向などを動的に切り替えられるようにしています。操作仕様は下記の通り。
カテゴリ 操作方法
回転の開始・停止 スペースキー押下
最大スピードの調整 ↑: スピードアップ, ↓: スピードダウン
回転方向の設定 ←: 反時計回り, →: 時計回り

2. 回転台の工作

  1. まずはA4サイズで印刷された工作シートから、四角いパーツと丸い大きなパーツをハサミで切り出します。特に四角いパーツは後でコレをガイドとして貼り付けしますので、できるだけ正確に切り取りましょう。なお、丸いパーツはしばらく使わないです。
    image.jpeg

  2. ここでCD/DVDを取り出し、CD/DVDの内側の穴と切り取った四角いパーツの黒い丸がピッタリ合うように、裏側からテープで止めます。ここも出来るだけ正確に貼り付けます。
    image.jpeg

  3. 次に、CD/DVDを裏返して、四角いパーツにtoioコアキューブ専用プレート(LEGOの4*4プレートでも良い)を両面テープでつけます。この時、貼り付ける向きに注意してください。キューブを取り付けたとき、CD/DVDの中心に近い方にキューブのtoioロゴが来るように貼り付けます。専用プレートで言うと突起が付いている辺が中心に近くなる向きです。光に透かすと向きがはっきりとわかりますよ。
    image.jpegimage.jpeg

  4. それではキューブを取り付けて回転させてみましょう!四角いパーツの黒丸の中央に白い点があると思いますが、回転させてもこの白い点がブレていなければ成功です!多少はズレていても楽しめますが、大幅にずれている場合はこの時点で工作を何度かやり直してみてください。
    image.jpeg

3. サンプルでの動作確認

ベーシックなサンプル

  1. ここまでの設定・工作がうまくできているか確認するために、サンプルシートで動作確認をします。A4サイズで印刷されたストロボスコープのサンプルシートから、一番左上にある図形がらせん状に回転している絵のものを切り取り、CD/DVDに両面テープで張り付けます。丸いパーツはCD/DVDの直径12cmピッタリに作っていますので、CD/DVDの外枠に合うように正確に貼り付けます。工作側はこれにて完了です。
    image.jpeg

  2. 次に、iOS/iPad OS上のアプリStroboscopeを立ち上げましょう。1点だけ準備が必要で、一番左上にある設定メニューを開いて、FPSという項目を20に変更してください。『+』ボタンをタップすると変更できます。
    image.jpeg

  3. では先ほどのソフトで回してみましょう!ぐるぐると無限に形状が変化するアニメーションが見えたとおもいます!基本の操作はこんな感じですが、前述のとおり、PC上のキーボードの左右キーを押すと回転方向を変更することが出来ます。回転方向が変わるだけで、また違ったアニメーションに見えるのも不思議ですね。なお、このサンプルはらせん状に描くことでアニメーションとしてのコマ数を多くとるサンプルになっています。

スピードの異なるアニメーションのサンプル

  1. 次にサンプルシートから数字と目、立方体が描かれたシートを切り取り、同様にCD/DVDに張り付け、先ほどと同様に動作させます。ただ、先ほどと違いコマ数が減っていますので、なんだかせかせかして数字など読みにくいです。こんな時は、回転のスピードを下げましょう。これも前述のとおり、PC上のキーボードの上下キーを押すと回転スピードを変更することが出来ます。今回は、下キーを何度か押して38に設定し、また、Stroboscopeアプリ上のFPSも10へ下げてください。すると先ほどよりも視認性の高いアニメーションになったと思います。ただ画のカクツキは増えてしまいますので、作品によってこれらの設定をうまく使い分けてください。
    ※ 補足:実はサンプルシートには、お勧めのFPS/回転スピードの組み合わせが記載されていますので、暗記する必要はありません。
    image.png
  2. なお、このサンプルではその場にとどまるアニメーションの例、色の変化の例、回転の例、数字等の文字を変化させる例等を確認できます。

その他アニメーションのサンプル

  1. ここまでくれば使い方はお分かりかと思いますので、最後のサンプルをお楽しみください。唯一カラーで描かれたものがサンプルシートの右上にありますので、そちらを切り取り、(FPS/回転スピード)=(13,30)で動作させます。こちらはエドワード・マイブリッジ(Eadweard Muybridge)さんという方が1893年に作成したフェナキストスコープ用円板です。当時は鏡やスリットを駆使してアニメーションを見ていたようです。

4. 自分でアニメーションを作る

さて、各種サンプルで遊んでいただければ、なんとなくどういう風にアニメーションさせるかはお分かりかと思います。今回は自分でも作成が出来るように、アニメーション作成のためのテンプレートもご用意しています。一番最初に切り出した丸いパーツを取り出してください。
image.jpeg

このパーツには、目安としてうっすら、円を8等分する線と同心円上の円の線が描かれていますので、それを基準にご自分のイラストや工作を載せてみてください。平面のイラストである必要はなく、立体物でも大丈夫というのが本件の面白いところの一つですね。

この時最も注意すべき点は、イラストや工作物を設置する向きです。ついつい画像のNGケースのように、自分に対して正面を向くように配置しがちですが、回転してアニメーションさせますので、あくまで円の中心に向かう方向を0度として扱ってください。
okng.png

線に沿って色々なものを配置するだけで不思議なアニメーションが量産できます!ぜひ楽しんでください。

所感と考察

  • まずは、楽しいアプリStroboscopeを作成されたMasayuki INOUEさんとパンタグラフさんに、お礼申し上げます。
  • 最初のらせん状に描かれたサンプルはp5.jsで描画しています。いつもは当然、画面上でアニメーションさせるものを描いていますが、これが現実世界で動き出す体験はまた新しい表現が誕生したなと感じました。
  • 回転方向や回転スピードの動的な変更、複数台による連携動作など、このツールとtoioを使って新しい表現がうまれることを期待します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【超簡単】Firebase で無料で作るハイスコアDB

前回までの砂漠のひつじ

無料プログラム学習用ピコピコゲーム砂漠のひつじを作成しつつ、その過程を記事にしている。
本記事はハイスコア実装編4回目として、無料DBの選定、調査の経過として、Firebaseアカウント作成から簡単なDB操作までを行っている。

前回までの記事では、Azure CosmosDBの動作を一通り確認しアーキテクチャが必要以上に複雑と感じFirebaseを調査することとしていた。

前回までの記事:
- Azure Cosmos で無料で作るハイスコアDB(1)
- Azure Cosmos で無料で作るハイスコアDB(2) : APIとデータモデルとAzureテーブル
- Azure Cosmos で無料で作るハイスコアDB(3) : コア(SQL)

今回の調査を終えての結論を述べると、学習コスト / 利用しやすさは以下の様に感じた。

Firebase Cloud Firestore(簡単) << AWS DynamoDB <<<(超えられない壁)<< Azure CosmosDB(難しい)

以下、Firebase登録から、レコード登録、取得までを解説する。

Firebaseアカウント登録

Googleアカウントを持っていれば、一切情報入力なしで一瞬で登録完了する。

Firebase:料金ページのファビュラスではなくジェネラスなリミットのSparkプランの項目の内容に目を通して、「無料Sparkプラン」項目にある[すぐに開始可能]ボタンを押下。

00_firebase_register.png

プロジェクト作成

Firebaseアカウント登録が完了したらコンソールへ移動。
[プロジェクトを追加]ボタンを押下しプロジェクトを作成する。

プロジェクト名を入力し、GoogleAnalyticsの利用設定を行えば完了。
無料プロジェクトの作業はアクセス数ぐらいしかモチベーションがないので利用する設定にしておいたが、画面キャプチャは省略している。

10_firebase_console.png
20_firebase_project_01.png

DB設定

Cloud Firestore

プロジェクトの作成が終わったら、プロジェクトHome画面左のナビゲーションバーよりCloud Firestore を選択し、[データベースの作成]を押下し、任意の名前のデータベースを作成する。

30_cloud_firestore.png

作成時、テストモードにするとガバガバになるので注意が必要。

31_cloud_firestore_test.png

ロケーションは、asia-northeast1を選択。

32_cloud_firestore_location.png

コレクションを開始

RDBで言うところのテーブルに相当するのがFirebaseのコレクション。
コレクション登録時にレコードを1件登録するUIになっているのは賛否ありそうだが個人的にはよいと感じた。

40_db.png

レコード登録時にドキュメントIDを省略すると自動で一意のIDが振られるのも好印象。

41_db_collection.png
42_db_collection.png

アプリ設定

アプリ作成

今回はWebページで利用するので、プロジェクトのHome画面より、[</>]ボタン押下。
任意のアプリの名前をつける。

50_app.png
51_app2.png

※「このアプリのFirebase Hostingも設定します。」について
Firebase Hosting を使うと Firebase CLI の設定が簡単になったりするがお高い模様。
今回はCDNからFirebaseのライブラリを取得しており、GitHub Pagesで公開しているのでいずれにしてもチェックはしない。

html に初期化コード追加

初期化コードが出力されるので、htmlにコピペする。

53_app3.png

コメントにTODOの記載がある通り、firestoreにアクセスするためライブラリを追加する。

index.html
<!-- firebase
執筆時点バージョンは、7.24.0。ドキュメントによりバージョン番号が異なる。
コンパネで取得できた初期化コードのバージョンに合わせるのがよさそう。
-->
<script src="https://www.gstatic.com/firebasejs/7.24.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.24.0/firebase-analytics.js"></script>

<!-- 利用したい機能を追加 -->
<script src="https://www.gstatic.com/firebasejs/7.24.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.24.0/firebase-firestore.js"></script>

<!-- 初期化部分は別ファイルにしておく -->
<script src="./firebase/init-firebase.js"></script>
<!-- firebase -->

スコア登録処理(js)

collection名を指定して、add。
CosmosDBでやってた作業はなんだったのか。

sample.js
var db = firebase.firestore();
db.collection('scores').add({
    name: 'name',
    score: 1000
}).then((r) => {
    console.log(r); // 登録成功したレコードの内容を表示。r.id に一意のIDが設定されている。
}).catch((err) => {
    console.log(err);   // エラー内容を表示
})

スコア取得処理(js)

コレクションに対して、where, orderBy, limit を指定して任意のレコード取得可能。
get()で全件取得も可能。

sample.js
// Queryを作る。where 句も対応しているが今回は不要のため未実装。
var q = db.collection('scores').orderBy('score', 'desc').limit(5);

// 非同期で取得。docsに配列形式で格納されており、.data() で json オブジェクトを取得できる。
q.get().then((r) => {
    for(var d of r.docs) {
        console.log(d.data());
    }
})

おわりに

簡単過ぎてビックリしました。

apiKeyをさらすことには一抹の不安がありましたが、以下記事によると大丈夫そうなので安心しました。
Firebase apiKey ってさらしていいの? ほんとに?

次回は実際にアプリに組み込もうかと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Minecraftっぽいアンビエントオクルージョン(AO)

アンビエントオクルージョン(AO)とは

遮蔽や環境光の反射などを模して陰影をつけることでより自然な影を演出する効果のこと。

AO無し / AOあり

MinecraftにおけるAO

本来AOは曲線などの複雑な影を計算する必要がありますが、Minecraftではキューブ状の地形なので、これを単純なアルゴリズムで再現することができます。
この図はキューブの各頂点の明るさを4段階に分類したものです。
Minecraftでは他にも各ブロックに対する明るさレベルがありますが、このような分類のAOマップで成り立っています。
aovoxel2.png

Minecraftでは完全にはこれに当てはまらず、各面2枚の3角形ポリゴンに対してそれぞれAO計算を行っており、それによる不具合もありますが、ここでは省きます。

AOテクスチャの作成

では先程の頂点の明るさの分類を元にテクスチャを作成してみます。
各頂点の側面と角の3方向の空気/障害物を0/1とする値として、以下の関数を使ってこの明度値を取得します。

function vertexAO(side1, side2, corner) {
  if(side1 && side2) {
    return 0
  }
  return 3 - (side1 + side2 + corner)
}

それぞれ4つの頂点の明るさを取得したら、各頂点を1ピクセルとするグレイスケールのAO画像を作成します。

// 4x4のcanvasを作成
let canvas = document.createElement("canvas");
canvas.setAttribute("width", 2);
canvas.setAttribute("height", 2);
let ctx = canvas.getContext('2d');

//明度曲線テーブル
const cols = [0.4*255, 0.6*255, 0.75*255, 1.0*255];

//light_level: 頂点の明るさ

let col = cols[light_level[0]];
ctx.fillStyle = "rgb(" + col + ", " + col + ", " + col + ")";
ctx.fillRect(0, 0, 1, 1);

col = cols[light_level[1]];
ctx.fillStyle = "rgb(" + col + ", " + col + ", " + col + ")";
ctx.fillRect(1, 0, 1, 1);

col = cols[light_level[2]];
ctx.fillStyle = "rgb(" + col + ", " + col + ", " + col + ")";
ctx.fillRect(1, 1, 1, 1);

col = cols[light_level[3]];
ctx.fillStyle = "rgb(" + col + ", " + col + ", " + col + ")";
ctx.fillRect(0, 1, 1, 1);

let texture = new THREE.CanvasTexture(canvas);
texture.magFilter = THREE.LinearFilter; //アンチエイリアスで拡大させる(省略可)

//メッシュに適用させる
mesh.material.aoMap = texture;

作成されるAOテクスチャの例
アンチエイリアス無し / アンチエイリアス有り
ao_texture.png scaled_ao.png

通常のテクスチャのみ
texture_only.png

AOマップ適用後
bombed.png

Three.jsにおけるAOマップの注意

先程のソースはMeshのMaterialにそのまま適用させましたが、Three.jsではそのままでは正しく表示されません。
なぜかというと、テクスチャマップである、GeometryのfaceVertexUVsにはデフォルトではAOマップ用のレイヤーが無いからです。
ただ、これは普通のテクスチャマップのコピーを追加させるだけで良いので難しくはありません。

THREE.Geometry.jsのソースの一部を拝借して作成した関数。

// faceVertexUvsにAOマップ用のレイヤーを追加する
function addAOVertexUVs(mesh){
    mesh.geometry.faceVertexUvs[1] = [];

    for(let j=0; j<mesh.geometry.faceVertexUvs[0].length; j++){

        let uvs = mesh.geometry.faceVertexUvs[0][j];
        let uvsCopy = [];

        for(let k=0; k<uvs.length; k++){

            uvsCopy.push( uvs[k].clone() );

        }
        mesh.geometry.faceVertexUvs[1].push( uvsCopy );
    }
}

参考元ページ

以下のページの一部画像を使用、内容を参考にさせていただきました。
0 FPS - Ambient occlusion for Minecraft-like worlds

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptについての備忘録

JavaScriptについて、備忘録としてまとめる。

関数の書き方

function命令で定義

function 関数名(引数, ...){
 ...任意の処理...
 return 戻り値;
}

Functionコンストラクター経由で定義

  • 関数が受け取る仮引数を順に並べ、最後に関数の本体を指定する。
  • JavaScriptの関数は原則として、function命令, または関数リテラル/アロー関数で定義する
var 変数名 = new Function(引数,...,関数本体);

例
var getArea = new Function('base', 'height', 'base' * 'height');

関数リテラル表現で定義する

  • JavaScriptにおいて関数はデータ型の一種
  • リテラルとして表現でき、関数リテラルを変数に代入したり、ある関数の引数として渡したり、戻り値として関数を返すことが可能
var 変数名 = function(変数、 変数) {...処理...};

例
var getArea = function(base, height) { base * height}
  • ES2015でが、オブジェクトリテラルの構文を改善し、プロパティ/メソッドをよりシンプルに表現できる
名前(引数) {...処理...}

例
run() {
  return 'tokotoko'
}

*function命令と関数リテラルの違い
- function命令 : 関数getAreaを直接定義
- 関数リテラル  : 「function(base,height {...}」と名前のない関数を定義し、変数getAreaに格納している

アロー関数で定義する

(引数...) => {...関数の本体...}

例
let getArea = (base,height)=> { return base * height }

ブロックを表す{...}は省略可能

let getArea = (base,height) => base * height;

引数が1個の場合には、引数をくくる()も省略可能

let price = cost => cost * 1.08;

JavaScriptにおけるオブジェクト指向

最もシンプルな「クラス」

  • JavaScriptでは関数(Functionオブジェクト)にクラスとしての役割を与えている。
var Member = function(){};

var mem = new Member();

コンストラクターで初期化する

  • コンストラクターとはインスタンスを生成する際に、オブジェクトを初期化する処理を記述するための特殊なメソッド
  • thisキーワードは、コンストラクターによって生成されるインスタンスを表す
  • this.プロパティ名 = 値;でプロパティを指定でき、文字列や整数、日付を指定できるだけでなく、関数オフジェクトも指定できる。
var Member = function(firstName,lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.getName = function() {
      return this.lastName + '' + this.firstName;
    }
};
  • クラスという抽象的な設計図が存在しないのがJavaScriptの世界
  • JavaScriptの世界にあるのは、あくまで実体化されたオブジェクトだけで、新しいオブジェクトを生成するにも(クラスではなく)オブジェクトがもとになっている。

オブジェクトの継承

アクセサーメソッド

  • プロパティそのものはクラス外部からアクセスできなようにして、代わりにプロパティにアクセスするためのメソッド

get/set

get: function() {
  return プライベート変数
},
set: function(value) {
  プライベート変数 = value

クラス定義

クラスの定義

class クラス名 {
  ...コンストラクターの定義...
  ...プロパティの定義...
  ...メソッドの定義...
}

クラスのコンストラクター

  • インスタンスを生成する際に引数として文字列や数値を受け取るために用意する。
メソッド名(引数...) {
 ...メソッドの本体...
}

例
constructor(email, password) {
   this.email = email;
   this.password = password
}

既存のクラスを継承

  • extendsの使い方
class Human {
  get walk() 
     return 'tokotoko'
  }
}

class Man extends Human {
  run() {
     return 'dodododo'
  }
}

let keigo = new Man
console.log(keigo.walk());  //結果:tokotoko
console.log(keigo.run());  //結果:dododo 

モジュールの基本

  • モジュールは1つのファイルとして定義するのが基本
  • モジュール内はデフォルトでは非公開.
  • exportで指定する必要がある。
lib/Utill.js
export class Human { ...中略... }
export class Cat { ...中略... }

以下のようのインポート

main.js
import { Human, Cat } from './lib/Util'
import命令記法
import { name, ...} from module
   name:インポートする要素
   module:モジュール(拡張子を抜いたパス)
  • アスタリスクを(*)でモジュール内での全ての要素をインポートできる
import * as animals form '.lib/Util'
  • モジュールに含まれる要素が1つだけであれば、デフォルトのエクスポートを宣言できる
./lib/Area.js
export default class {
  static getArea(base,height) {
   return base*height
  };
}

参考文献
JavaScript本格入門

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのdictionaryを値でソートする(自分用メモ)

自分用メモ

jQueryを使わずにJavaScriptのdictionaryを値でソートする.

参考URL:https://stackoverflow.com/questions/25500316/sort-a-dictionary-by-value-in-javascript

sort.js
    function sort_object(obj) {
      items = Object.keys(obj).map(function(key) {
          return [key, obj[key]];
      });
      items.sort(function(first, second) {
        return second[1] - first[1];
      });
      var sorted_obj={};
      for (var i=0; i< items.length;i++){
          use_key=items[i][0];
          use_value=items[i][1];
          sorted_obj[use_key] = use_value;
      }
      return(sorted_obj);
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】javascriptのお手軽スクロールアニメーション(ScrollReveal.js使用)

目標

scroll.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

ScrollReveal.jsとは

https://scrollrevealjs.org/
こちらが公式サイトにはなります。
ScrollReveal is a JavaScript library for easily animating elements as they enter/leave the viewport.
ScrollRevealは、要素がビューポートに出入りするときに要素を簡単にアニメーション化するためのJavaScriptライブラリです。
※google翻訳

流れ

1 ScrollReveal.jsを導入する
2 viewの編集
3 jsファイルの編集

ScrollReveal.jsを導入する

①CDNで読み込む場合(おすすめ)
application.html.erbのhead内に
<script src="https://unpkg.com/scrollreveal">
この一行を追加し、ScrollReveal.jsを使用できるようにします。

app/views/layouts/application.html.erb
<head>
  <title>Ddtt</title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  <script src="https://unpkg.com/scrollreveal"></script>
</head>

②ファイルをダウンロードする場合
https://github.com/jlmakes/scrollreveal
こちらからzipファイルダウンロードするし、中にある「scrollreveal.min.js」を
app/assets/javascripts内に保存します。
その後、<script src="/js/scrollreveal.min.js"></script>
こちらをhead内または表示ファイルの一番上に追加してください。

view,CSSの編集

説明のため、html内にcssを記述します。

app/views/homes/top.html.erb
<div class="page">
  <span>スクロールしてください</span>
</div>

<div class="page">
  <div class="box"></div>
</div>

<style>
.page {
  position: relative;
  height: 100vh;
}
.box {
  width: 500px;
  height: 200px;
  background-color: red;
}
</style>

jsファイルの編集

こちらが基本の形。

app/asstes/javascripts/application.js
$(function(){
  ScrollReveal().reveal('.box');
});

基本形だとこのようになります。
画面収録 2020-10-23 20.11.11.mov.gif
gif画像にした分表示がかなり早くなっていますが、
ご覧の通りあまりアニメーションがあるかどうかは確認しにくいです。
したがってオプションを付けていきます。

目標にある動画の記述。

app/asstes/javascripts/application.js
$(function(){
  ScrollReveal().reveal('.box', { 
    duration: 2000, 
    scale: 4,
    reset: false
  });
});

このようにオプションを追加することも可能です。
今回使用したオプションは

  • duration:アニメーションの完了にかかる時間
  • scale:表示される前の要素のサイズ
  • reset:viewportを離れる時に初期化された位置に戻る要素を有効/無効にする

その他にも様々なオプションが用意されているため、
興味のある方は公式サイトをご覧ください。
https://scrollrevealjs.org/api/delay.html

まとめ

ほとんどの有名サイトにはなにかしらのアニメーションが付与されており、
今から作成する場合は必須になっていると思います。
ただし、上記を活用すれば数分で導入できるのでおすすめです」。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テストの組み合わせを洗い出す

テストの組み合わせを洗い出すプログラムを書いてみました。
テストケースを削らせてもらえないストイックな現場にいる人に役立つかもしれません。

テストの組み合わせ

例えば、性別「男・女」、職業「学生・会社員・その他」の場合、組み合わせは 2 * 3 = 6 通りになります。下表の組み合わせです。

性別 職業
学生
会社員
その他
学生
会社員
その他

これくらいだとすぐに書き出せるのですが、パラメータが増えて組み合わせが100通り、200通りにもなった場合、書き出すのが困難になってきます(面倒だし、頭が混乱してくる)
面倒なので、テストケースを削りたくなってきますが、削る基準を考えるのも面倒ですし、ストイックな現場だと100、200程度なら全部やれと言われるでしょう。

プログラム

そういうときにテストケースを洗い出すプログラムがあれば便利です。
以下、例として、プリンタの詳細設定の組み合わせを出力するプログラムを書いてみます。
combination関数が組み合わせを出力するプログラムになっています。
HTMLファイルとして保存して、ブラウザで開くと、実行できます。

combination.html
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Combination</title>
  <script>
    var p1 = ['Letter', 'A4'];
    var p2 = ['1', '2', '4', '6', '9', '16'];
    var p3 = ['既定', 'なし', '最小', 'カスタム'];
    var p4 = ['既定', 'カスタム'];
    var p5 = ['ヘッダーとフッター', '背景のグラフィック'];

    var resultBuffer = '';

    combination(p1, p2, p3, p4, p5);

    function combination() {
      combinationInternal(arguments, 0, arguments[0], '');
      document.write('<pre>' + resultBuffer + '</pre>')
    }

    function combinationInternal(allParams, idx, params, result) {
      for (var i = 0; i < params.length; i++) {
        if (allParams.length - 1 === idx) {
          resultBuffer += (result + params[i] + '\r\n');
        } else {
          combinationInternal(allParams, idx + 1, allParams[idx + 1], result + (params[i] + '\t'));
        }
      }
    }
  </script>
</head>
<body>
</body>
</html>

実行結果

実行結果は以下になります。
長いので、途中から省略していますが、2 * 6 * 4 * 2 * 2 = 192パターン出力されます。

実行結果
Letter  1   既定  既定  ヘッダーとフッター
Letter  1   既定  既定  背景のグラフィック
Letter  1   既定  カスタム    ヘッダーとフッター
Letter  1   既定  カスタム    背景のグラフィック
Letter  1   なし  既定  ヘッダーとフッター
Letter  1   なし  既定  背景のグラフィック
Letter  1   なし  カスタム    ヘッダーとフッター
Letter  1   なし  カスタム    背景のグラフィック
Letter  1   最小  既定  ヘッダーとフッター
・・・・・・・・・・(省略)・・・・・・・・・・
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Maps Geocoding APIのJavaScriptをわかりやすく丁寧に解説

はじめに

先日ポートフォリオにGoogle Maps APIを取り入れて地図表示機能を実装したのですが、
そこで書いたJavaScriptのコードの理解が曖昧だったのでまとめてみました。

この記事ではGoogle Maps APIの導入方法ではなく、JavaScriptのコードにフォーカスして解説します。
APIの導入の仕方についてはこちらの記事では解説しませんので、知りたい方は以下の記事をご覧ください。
【Rails6 / Google Map API】初学者向け!Ruby on Railsで簡単にGoogle Map APIの導入する

「ネットにある記事をコピペしたら何となくできたけどコードの内容が理解できない」
という方がいましたら読んでいただければと思います。

前提知識

住所や地名を緯度や経度などの地理座標に変換することを「ジオコーディング」と言います。
Google MapsのGeocoding APIは、ジオコーディングをするAPIです。

解説

先日旅行をしたい人がツアーガイドを募集できるアプリを制作したのですが、
そこで旅行したい場所として入力した場所が地図に表示されるように実装しました。

スクリーンショット 2020-10-23 22.18.23.jpg

ビューのソースコードは以下のとおりで、
旅行したい場所を表示する箇所にaddressのidを、地図を表示する場所にmapのidを付与しています。

show.html.haml
    .Post_main__Box
      .Post_show_title
        = @post.title
      .Post_table.Text
        %table
          %tr
            %th 旅行したい場所
            %td#address  // ここに住所を表示
              = @post.region
          %tr
            %th 希望日時
            %td
              = @post.datetime
          %tr
            %th 希望料金
            %td
              = @post.charge
          %tr
            %th お支払い方法
            %td
              = @post.payment
      .Post_head
        = "-リクエスト内容-"
      .Post_content
        = simple_format(@post.content)
      .Post_head
        = "-地図-"
      .Post_map#map   // ここに地図を表示

さらに、JavaScriptのソースコードは以下のとおりです。

map.js
// ページの読み込みが終わった後に処理が行われるように設定
window.addEventListener('load', function() {
  const inputAddress = document.getElementById('address').textContent;    //①
  const target = document.getElementById('map');    //②
  geocoder = new google.maps.Geocoder()   // ③

  geocoder.geocode( { address: inputAddress}, function(results, status) {  // ④
    if (status == 'OK') {  // ⑤
      const map = new google.maps.Map(target, {  // ⑥
        center: results[0].geometry.location,   // ⑦
        zoom: 13  // ⑧
      });
      new google.maps.Marker({  // ⑨
          map: map,  // ⑩
          position: results[0].geometry.location  // ⑪
      });
    } else {   // ⑫
      document.getElementById('map').style.height = '20px'   // ⑬
      document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
    }
  });   
})

上記のJavaScriptのコードについて解説していきます。

▼①と②について

const inputAddress = document.getElementById('address').textContent;   //①
const target = document.getElementById('map');   //②

①ではaddressのidを持った要素の中にある文字列(ここでは住所)を取得し、inputAddressに代入しています。
②ではmapのidを持った地図を表示する領域のdiv要素のオブジェクトをtargetに代入しています。

▼③について

geocoder = new google.maps.Geocoder()

この記述では、Googleサーバーと通信するために必要なgoogle.maps.Geocoderのオブジェクト(インスタンス)を生成しています。
APIには、このオブジェクトを通してアクセスします。

▼④について

geocoder.geocode( { address: inputAddress}, function(results, status) {   

ここではまず、①で生成したgeocoderオブジェクトにgeocode()メソッドを用いることで,
ジオコーディングをするためのリクエストを送信しています。

リクエストを送信するときは、APIの仕様でaddresslocationplaceIdのどれかの値を渡さなくてはならず、
上記のコードではaddressのプロパティに①で定義したinputAddressの値を入れてパラメーターとして渡しています。

リクエストが完了すると結果(results)とステータス(status)が返ってくるので、
それらを取得して処理するために、resultsstatusを引数にコールバック関数を記述します。

▼⑤について

if (status == 'OK')

リクエストの結果として返されるステータスでは、ジオコーディングが成功した場合にはOKが返され、
成功しなかった場合にはERRORなどといったコードが返されます。
上記の記述では、ジオコーディングが成功した場合のことを表しています。

▼⑥〜⑧について

const map = new google.maps.Map(target, {  // ⑥
  center: results[0].geometry.location,   // ⑦
  zoom: 13  // ⑧
});

⑥では、new google.maps.Mapで地図を生成し、mapに代入しています。
google.maps.Mapクラスのコンストラクタでは、1番目の引数には地図を表示するdiv要素を指定します。
ここでは、②で定義したtargetを指定しています。
また、2番目の引数には、地図の座標やズームレベルを設定するオブジェクトを指定します。

⑦では、results[0].geometry.locationでリクエストの結果の中から経度と緯度の情報を取得し、
その地理座標を地図の真ん中に表示するように記述しています。
ちなみに、リクエストの結果は配列で返されるためresults[0]と記述しています。

さらに⑧でズームレベルを指定しています。
この数値が大きければ大きいほど地図は拡大して表示されます。

▼⑨〜⑪について

new google.maps.Marker({  // ⑨
    map: map,  // ⑩
    position: results[0].geometry.location  // ⑪
});

ここでは、地図上にマーカー(赤いピン)を表示させる記述をしています。
⑨でマーカーのオブジェクトを生成し、引数にオプションとしてmappositionの指定をしています。
⑩ではマーカーを表示する地図を指定しており、ここでは⑥で定義したmapを指定しています。
また、⑪ではマーカーを表示する位置をリクエストの結果から得られた地理座標で指定しています。

ちなみに、オプションでanimation: google.maps.Animation.DROPを追加すると、
マーカーが上から落ちてくるようなアニメーションを追加できます。

▼⑫〜⑭について

} else {   // ⑫
  document.getElementById('map').style.height = '20px'   // ⑬
  document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
}

ここでは、ジオコーディングが成功しなかった場合の処理を記述しています。
⑬で地図を表示させるdiv要素の高さを変更し、⑭でHTMLの中身を文字に書き換えています。
このように記述すると、以下のように表示されます。
スクリーンショット 2020-10-24 12.17.01.jpg

参考にした記事

この記事を投稿するにあたり、以下の記事を参考にさせていただきました。
以下の記事ではもっと詳細に書かれているので、詳しく知りたい方はご覧ください。
Geocoding Service  |  Maps JavaScript API  |  Google Developers
Google Maps API の使い方 利用方法 / Web Design Leaves
ジオコーディング - マッピィ Google Maps API JavaScriptの使い方 -

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Maps Geocoding APIのJavaScriptを理解する

はじめに

先日ポートフォリオにGoogle Maps APIを取り入れて地図表示機能を実装したのですが、
そこで書いたJavaScriptのコードの理解が曖昧だったのでまとめてみました。

この記事ではGoogle Maps APIの導入方法ではなく、JavaScriptのコードにフォーカスして解説します。
APIの導入の仕方についてはこちらの記事では解説しませんので、知りたい方は以下の記事をご覧ください。
【Rails6 / Google Map API】初学者向け!Ruby on Railsで簡単にGoogle Map APIの導入する

「ネットにある記事をコピペしたら何となくできたけどコードの内容が理解できない」
という方がいましたら読んでいただければと思います。

前提知識

住所や地名を緯度や経度などの地理座標に変換することを「ジオコーディング」と言います。
Google MapsのGeocoding APIは、ジオコーディングをするAPIです。

解説

先日旅行をしたい人がツアーガイドを募集できるアプリを制作したのですが、
そこで旅行したい場所として入力した場所が地図に表示されるように実装しました。

スクリーンショット 2020-10-24 13.16.03.jpg

ビューのソースコードは以下のとおりで、
旅行したい場所を表示する箇所にaddressのidを、地図を表示する場所にmapのidを付与しています。

show.html.haml
    .Post_main__Box
      .Post_show_title
        = @post.title
      .Post_table.Text
        %table
          %tr
            %th 旅行したい場所
            -# ここに住所を表示
            %td#address
              = @post.region
          %tr
            %th 希望日時
            %td
              = @post.datetime
          %tr
            %th 希望料金
            %td
              = @post.charge
          %tr
            %th お支払い方法
            %td
              = @post.payment
      .Post_head
        = "-リクエスト内容-"
      .Post_content
        = simple_format(@post.content)
      .Post_head
        = "-地図-"
      -# ここに地図を表示
      .Post_map#map

さらに、JavaScriptのソースコードは以下のとおりです。

map.js
// ページの読み込みが終わった後に処理が行われるように設定
window.addEventListener('load', function() {
  const inputAddress = document.getElementById('address').textContent;    //①
  const target = document.getElementById('map');    //②
  geocoder = new google.maps.Geocoder()   // ③

  geocoder.geocode( { address: inputAddress}, function(results, status) {  // ④
    if (status == 'OK') {  // ⑤
      const map = new google.maps.Map(target, {  // ⑥
        center: results[0].geometry.location,   // ⑦
        zoom: 13  // ⑧
      });
      new google.maps.Marker({  // ⑨
          map: map,  // ⑩
          position: results[0].geometry.location  // ⑪
      });
    } else {   // ⑫
      document.getElementById('map').style.height = '20px'   // ⑬
      document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
    }
  });   
})

上記のJavaScriptのコードについて解説していきます。

▼①と②について

const inputAddress = document.getElementById('address').textContent;   //①
const target = document.getElementById('map');   //②

①ではaddressのidを持った要素の中にある文字列(ここでは住所)を取得し、inputAddressに代入しています。
②ではmapのidを持った地図を表示する領域のdiv要素のオブジェクトをtargetに代入しています。

▼③について

geocoder = new google.maps.Geocoder()

この記述では、Googleサーバーと通信するために必要なgoogle.maps.Geocoderのオブジェクト(インスタンス)を生成しています。
APIには、このオブジェクトを通してアクセスします。

▼④について

geocoder.geocode( { address: inputAddress}, function(results, status) {   

ここではまず、①で生成したgeocoderオブジェクトにgeocode()メソッドを用いることで,
ジオコーディングをするためのリクエストを送信しています。

リクエストを送信するときは、APIの仕様でaddresslocationplaceIdのどれかの値を渡さなくてはならず、
上記のコードではaddressのプロパティに①で定義したinputAddressの値を入れてパラメーターとして渡しています。

リクエストが完了すると結果(results)とステータス(status)が返ってくるので、
それらを取得して処理するために、resultsstatusを引数にコールバック関数を記述します。

▼⑤について

if (status == 'OK')

リクエストの結果として返されるステータスでは、ジオコーディングが成功した場合にはOKが返され、
成功しなかった場合にはERRORなどといったコードが返されます。
上記の記述では、ジオコーディングが成功した場合のことを表しています。

▼⑥〜⑧について

const map = new google.maps.Map(target, {  // ⑥
  center: results[0].geometry.location,   // ⑦
  zoom: 13  // ⑧
});

⑥では、new google.maps.Mapで地図を生成し、mapに代入しています。
google.maps.Mapクラスのコンストラクタでは、1番目の引数には地図を表示するdiv要素を指定します。
ここでは、②で定義したtargetを指定しています。
また、2番目の引数には、地図の座標やズームレベルを設定するオブジェクトを指定します。

⑦では、results[0].geometry.locationでリクエストの結果の中から経度と緯度の情報を取得し、
その地理座標を地図の真ん中に表示するように記述しています。
ちなみに、リクエストの結果は配列で返されるためresults[0]と記述しています。

さらに⑧でズームレベルを指定しています。
この数値が大きければ大きいほど地図は拡大して表示されます。

▼⑨〜⑪について

new google.maps.Marker({  // ⑨
    map: map,  // ⑩
    position: results[0].geometry.location  // ⑪
});

ここでは、地図上にマーカー(赤いピン)を表示させる記述をしています。
⑨でマーカーのオブジェクトを生成し、引数にオプションとしてmappositionの指定をしています。
⑩ではマーカーを表示する地図を指定しており、ここでは⑥で定義したmapを指定しています。
また、⑪ではマーカーを表示する位置をリクエストの結果から得られた地理座標で指定しています。

ちなみに、オプションでanimation: google.maps.Animation.DROPを追加すると、
マーカーが上から落ちてくるようなアニメーションを追加できます。

▼⑫〜⑭について

} else {   // ⑫
  document.getElementById('map').style.height = '20px'   // ⑬
  document.getElementById('map').innerHTML = '該当する場所が見つかりませんでした。'   // ⑭
}

ここでは、ジオコーディングが成功しなかった場合の処理を記述しています。
⑬で地図を表示させるdiv要素の高さを変更し、⑭でHTMLの中身を文字に書き換えています。
このように記述すると、以下のように表示されます。
スクリーンショット 2020-10-24 13.16.20.jpg

参考にした記事

この記事を投稿するにあたり、以下の記事を参考にさせていただきました。
以下の記事ではもっと詳細に書かれているので、詳しく知りたい方はご覧ください。
Geocoding Service  |  Maps JavaScript API  |  Google Developers
Google Maps API の使い方 利用方法 / Web Design Leaves
ジオコーディング - マッピィ Google Maps API JavaScriptの使い方 -
Google Maps JavaScript API入門

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Electron-Builderでnode.jsのパッケージを含めてビルドする際の注意点

screen0010.png

ElectronとExpressを使ったアプリを開発していたのだが、Electron-builderを使ってパッケージ化した際に、設置したはずのexpressが見つからないというエラーが表示された。

調べてみると、どうやらプロジェクト毎のnode_modulesnpm install --save-dev expressではなく、環境毎のnode_modulesnpm install --save expressである必要があるそうだ。

ちなみに、npm install --save expressでインストールした後にパッケージ化したものは、ちゃんとパッケージ内にexpressが内包されているらしく、別端末からも起動できた。

...
  "devDependencies": {
    "electron": "^10.1.4",
    "electron-builder": "^22.9.1"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AM送信所マップを作ってみた

AM放送局の送信所を地理院タイルにマーカーで表示してみます。

送信所のjsonを作ります。とりあえず東北の各県にある民放の一番出力の大きい送信所のみをデータにしてみました。

送信所の住所はでんぱでーたどっと混むさんで調べてGeocoding.jpさんで確認して微調整してあります。

https://gist.githubusercontent.com/yamori813/16065bbff4473e8ec3430570fcf7da7f/raw/4e1b1673465d247ae137aeb9fecec63015fc8128/radio.json

これを地理院タイルにマーカーを置きます。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>AM DX MAP</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script>
        function init() {
            $.getJSON("https://gist.githubusercontent.com/yamori813/16065bbff4473e8ec3430570fcf7da7f/raw/4e1b1673465d247ae137aeb9fecec63015fc8128/radio.json", null, function(data,status){
    //取得成功したら実行する処理

                var map = L.map('mapcontainer', { zoomControl: false });
                var mpoint = [35.8627, 139.6072];
                map.setView(mpoint, 6);
                L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/blank/{z}/{x}/{y}.png', {
                    attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>"
                }).addTo(map);
                for (var i = 0; i < data.radio.length; i++) {
                    //ポップアップする文字(HTML可、ここでは画像を表示)
                    var popup = L.popup().setContent(data.radio[i].name + " " + data.radio[i].frequency + "kHz");
                    //マーカーにポップアップを紐付けする。同時にbindTooltipでツールチップも追加
                    L.marker([data.radio[i].latitude,data.radio[i].longitude]).bindPopup(popup).bindTooltip(data.radio[i].corporation).addTo(map);
                }
            });
        }
    </script>
</head>
<body onload="init()">
    <div id="mapcontainer" style="position:absolute;top:0;left:0;right:0;bottom:0;"></div>
</body>
</html>

こんな感じになります。

Screenshot_2020-10-24 AM DX MAP.png

あとは全国版のjsonを作るだけ。

追記

全国版のjsonできました。広域大阪無線保全課さんの情報も大変参考になりました。

https://gist.githubusercontent.com/yamori813/16065bbff4473e8ec3430570fcf7da7f/raw/31db35e7436590cbc7ad5768f2ea46bd31eb1757/radio.json

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

? MS Teams 開発の初心者向けガイド その2: Bots

こんにちは。Microsoft Teams 開発シリーズ前回のチュートリアルを楽しんでもらえたことをを願っています。

これは、初心者シリーズの第二弾です。今回は、対話式のチャットボットを構築する方法を説明します。
2-bots-cover-1000x420.png
Teams アプリの作成方法を学ぶ方法にはさまざまな道のりがあるのですが、このチュートリアルでは、コンセプトを学んでもらうことを重視したいので、最低限のコードと最小限のツールセットを使用しています。また、マイクロソフト Azure から Bot をセットアップすることもできますが、今回はそのプロセスを使わず、どの環境でも実行することができます。 (MS 社員だから、ほんとは Azure の宣伝したほうがよいのだけど ?)


前回のチュートリアルでは、Teams クライアントにタブを埋め込む方法を紹介しましたが、このチュートリアルでは、全く異なる機能、botsを紹介します。

チームの機能: 「Bot」

タブ、メッセージ・エクステンション、など Teams アプリではいろいろな機能がありますが使えますが、Bot をうまく使えば、Teams 内でさまざまなワークフローを自動でやってもらうことができます。
Bot がコマンドをアクションに変換し、たとえば、タスクの生成、コードのレビュー、管理チケットのステータスの確認などを行う、などといったことができるようになります。
MS Teams bots

このチュートリアルで今からすること

さて、今から作っていくのは、みなさんが入力した言葉を、ただただ後ろから言って返すという単純な bot を作成します。正直これはまったく役に立つ bot ではないのですが、これがきっかけで、みなさんがもっといいアイデアを生むことを期待してます。

  1. App Studioでアプリを構成する
  2. ブラウザでうごく IDE でコードを設定し、実行する
  3. ボットフレームワークを使ってBot の会話を処理

最終的な結果は次のようになります。
bot-app-ja.png

? 必須科目

Teams にアプリをインストールできるようにするには、組織の管理者がアクセス許可を付与する必要があります。
それ以外の場合は、無料のMicrosoft 365 開発者プログラム に登録しましょう。このプログラムでは、開発者テナントのサンドボックス、サンプル データ パックに付属しているモック ユーザーデータなどが使え、サブスクリプションはなどでもリニューアルできます。

  • 開発の許可がある Teams テナント、または開発専用テナント (M365 開発者プログラムにサインアップしよう
  • App Studio - チームクライアントのアプリメニューからアプリを探し、テナントのワークスペースにインストールしてね
  • Node.js の基礎知識

Building a chat bot

? コード サンプルの取得

このチュートリアル シリーズでは、プロジェクトのコードのホスティングと実行を簡略化するために、サードパーティのツール、Glitchを使用しています。

Glitch は、node.jsコードを記述して実行できるWebベースのIDEなので、少なくとも今のところ、localhostのトンネル、デプロイを気にすることなく、Teamsアプリ開発の概念と基本を学ぶことに集中できます。(Glitch はチュートリアルのために使っていますが、本来は開発に必要ありません。今後ゆくゆく Azure へのデプロイも含め、しっかりカバーしていきたいと思います。)

まず、この Glitch プロジェクトの remix ができるリンクをクリックしてください。リミックスとは GitHub で言うところのリポジトのをフォークのようなようなもので、自分用のプロジェクトのコピーが生成されるため、元のコードに影響なく自分用に好きなように変更できます。
Remix on Glitch
さて、自分専用プロジェクトのリポを取得すると、自動的に独自のWebサーバーURLを取得します。たとえば、生成されたプロジェクトは、3単語ほどでできたランダムな語で構成されています。たとえばそのプロジェクト名が achieved-diligent-bell だったら、ウェブサーバーのURLは https://achieved-diligent-bell.glitch.me になります。必要に応じて名前をカスタマイズすることもできます。
glitch project name

⚙️ App Configuration: App Studioを使ってアプリ マニフェストを作成

Teams 用のアプリを作成する場合は、Teams クライアントにインストールするアプリ パッケージを作成する必要があります。パッケージには以下が含まれます。

? your-app-package
    └── ? manifest.json
    └── ? color.png (192x192)
    └── ? outline.png (32x32)

残りの、アプリに必要なコードと画像などのアセットは、Web サーバーでホストする必要があります。(このチュートリアルでは、 Glitch からアプリを自動的にランするので特別なサーバの必要はありませんが、将来的に自分でアプリを作成する場合は用意してください。)
現時点ではマニフェスト ファイルを手動で作成するのではなく、App Studio というビジュアル ツールを使用してチーム クライアントに直接アプリ パッケージを作成、インストールできるようにします。

? Using App Studio

App Studio をまだインストールしていない方はインストール、すでにした場合は App Studio を開きます。

App Studio 上部の Manifest Editor(マニフェスト エディター) タブをクリックし、Create a new app(新しいアプリの作成)を選択します。

 App URLs セクションで、プライバシーと利用規約の Web ページ URL も入力します。この例では、プレースホルダ URL である、https://example.comを使用していますが、公開するアプリを開発する場合は、フェイクではない URL が必要になってきます。

そして Generate ボタンをクリックして App ID を生成してください。
bot-appstudio-01-details.png

? Configuring a bot

左側のメニューから、 Capabilities > Bots を選択

次に Set up をクリックして新しい bot を設定します。

Bot 名を入力し、ここでは Personal スコープを選択します。この個人用、パーソナル・ボットでは、bot と単一ユーザーの間で会話を行うことができます。 (スコープの詳細については、 Conversation basics 参照。)
bot-appstudio-02-new-bot.png
次に Generate new password ボタンをクリックします。ダイアログが開いたら、そこで表示されるパスワードをコピーしてください。次のステップに必要になります。
bot-appstudio-03-bot.png

? App credentials

ボット名の横にある ID (2cd53e8a-e698-4exx-... のような文字列) をコピーし、隠しファイルである.envファイルに環境変数として貼り付けます (.env-sample の名前を .env に変更します)。

App Passwordsの下で新規パスワードを生成し、それをコピーし、これも .env ファイルに貼り付けます。

これらの情報は、bot アダプターを初期化するために使用されます。(index.js を参照してください。

Messaging Endpoint で、bot サーバーを入力します。今回は、Glitch サーバ上でコードを動かしているので、 https://[your project].glitch.me/api/messages のように自分のプロジェクト名が入った URL がサーバとなります。

? App manifest package をインストール

Finish > Test and distribute へ行きます。

エラーが発生した場合は、それを修正してください、そうでなければ、Install をクリックしてクライアントにインストールしてください。
bot-appstudio-04-install.png
また、後でインストール、または配布するために、manifest.json と 2 つのアイコン画像を含む zip ファイルをダウンロードすることもできます。

チュートリアル通り、Glitch コード サンプルをリミックスしている場合は bot は既に動作するはずです。

でも bot を試す前に、これがどのようにコーディングされているかを簡単に説明してみましょう。

? Microsoft Bot Framework

マイクロソフト Bot Framework は、エンタープライズ・グレードの bot を構築できるオープンソース SDK です。

この SDK は、Teams だけでなく、Web やモバイル チャット、Skype、Facebook、Amazon Alexa、Slack、Twilio など、幅広い種類のチャット ボットで動作するように設計された強力なプラットフォームです。

? Initiating the bot service

まず、Glitch コードサンプルのリポジトリには、index.js、および bots.js に 2 つの JS ファイルがあります。

*注: Glitch は、事前定義された package.json からすべての依存モジュールを自動的にインポートするので、パッケージを手動でインストールする必要はありません。

index.js では、botbuilder ライブラリ、および HTTP サーバーと HTTP ルーティング要求を設定するためのライブラリを含める必要があります。ここでは私は Express を使用していますが、Restify など、他のものを使用することができます。

index.js:

// Import Express & set up HTTP server
const express = require('express');
const app = express();
const server = app.listen(process.env.PORT || 3978);

// Import bot services
const { BotFrameworkAdapter } = require('botbuilder');

// Bot's main dialog
const { ReverseBot } = require('./bot');

注: この例では、私は botbuilder のバージョン4.10.0を使用しています。コードが期待どおりに動作しない場合は、使用しているバージョンを確認してください!

次に、bot がユーザーと通信し、応答を送信できるようにするアダプターをセットアップします。

const adapter = new BotFrameworkAdapter({
  appId: process.env.MicrosoftAppId,
  appPassword: process.env.MicrosoftAppPassword
});

// Error handlings (See the Glitch sample for details!)

// Create the main dialog
const myBot = new ReverseBot();

? Bot ロジックへの要求の転送

Express を使用して、着信要求をリスニングするルーティングを処理します。

app.post('/api/messages', (req, res) => {
  adapter.processActivity(req, res, async context => {
    await myBot.run(context);
  });
});

前の手順で、 App Studio で URL を設定しました。/api/messages は、クライアント要求に応答するアプリケーションのエンドポイント URL です。

? 要求の処理とボットの返信の投稿

エンドポイントで要求を受信し、ボット ロジックに転送すると、アプリは要求のコンテキストを受け取り、bots.js でカスタム応答を作成します。

要求に対する適切なハンドラーを作成するために拡張された TeamsActivityHandler を参照してください。

const { TeamsActivityHandler, MessageFactory } = require('botbuilder');

class ReverseBot extends TeamsActivityHandler {
  constructor() {
    super();
    this.onMessage(async (context, next) => {
      const backward = [...context.activity.text].reverse().join(''); // reverse string
      const replyText = `? *${ backward }*`; // you can use markdown
      await context.sendActivity(MessageFactory.text(replyText));

      await next();
    });
  }
}

TeamsActivityHandler は、メッセージ イベント (*例えば onMembersAdded メソッドが会話にメンバーが追加されるたびに呼び出される) などのメッセージを処理し、返信を送信するチーム固有のクラスです。

例では、メッセージがクライアントに送信されると、onMessage がトリガーされ、メッセージ テキストを取得して、カスタム応答を作成するために使用できます。

?? Trying your bot

それでは、ボットを試してみましょう! Teams クライアントに移動し、左側のメニューバーからボットを起動するをクリックします。
すべてがちゃんと動作する場合は、次のように bot と会話できるはずです ??
bot-app-ja.png

この例では、テキスト返信を送信する方法のみを示しますが、ボタンやその他の UI コンポーネントを使用して、よりインタラクティブなメッセージを作成できます。これについては後で詳しく説明してゆきたいと思っています。

さて、チュートリアルを楽しんでいただけましたか?ぜひこれよりも良いユースケースを見つけて、素晴らしいアプリを作成することを願っています!

では、また次回 ?

?? この記事を英語で読みたいという方は dev.to のリンクからどうぞ!


? Learn more

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

? Microsoft Teams 開発の初心者向けガイド その2: Bots

こんにちは。Microsoft Teams 開発シリーズ前回のチュートリアルを楽しんでもらえたことをを願っています。

これは、初心者シリーズの第二弾です。今回は、対話式のチャットボットを構築する方法を説明します。
2-bots-cover-1000x420.png
Teams アプリの作成方法を学ぶ方法にはさまざまな道のりがあるのですが、このチュートリアルでは、コンセプトを学んでもらうことを重視したいので、最低限のコードと最小限のツールセットを使用しています。また、マイクロソフト Azure から Bot をセットアップすることもできますが、今回はそのプロセスを使わず、どの環境でも実行することができます。 (MS 社員だから、ほんとは Azure の宣伝したほうがよいのだけど ?)


前回のチュートリアルでは、Teams クライアントにタブを埋め込む方法を紹介しましたが、このチュートリアルでは、全く異なる機能、botsを紹介します。

チームの機能: 「Bot」

タブ、メッセージ・エクステンション、など Teams アプリではいろいろな機能がありますが使えますが、Bot をうまく使えば、Teams 内でさまざまなワークフローを自動でやってもらうことができます。
Bot がコマンドをアクションに変換し、たとえば、タスクの生成、コードのレビュー、管理チケットのステータスの確認などを行う、などといったことができるようになります。
MS Teams bots

このチュートリアルで今からすること

さて、今から作っていくのは、みなさんが入力した言葉を、ただただ後ろから言って返すという単純な bot を作成します。正直これはまったく役に立つ bot ではないのですが、これがきっかけで、みなさんがもっといいアイデアを生むことを期待してます。

  1. App Studioでアプリを構成する
  2. ブラウザでうごく IDE でコードを設定し、実行する
  3. ボットフレームワークを使ってBot の会話を処理

最終的な結果は次のようになります。
bot-app-ja.png

? 必須科目

Teams にアプリをインストールできるようにするには、組織の管理者がアクセス許可を付与する必要があります。
それ以外の場合は、無料のMicrosoft 365 開発者プログラム に登録しましょう。このプログラムでは、開発者テナントのサンドボックス、サンプル データ パックに付属しているモック ユーザーデータなどが使え、サブスクリプションはなどでもリニューアルできます。

  • 開発の許可がある Teams テナント、または開発専用テナント (M365 開発者プログラムにサインアップしよう
  • App Studio - チームクライアントのアプリメニューからアプリを探し、テナントのワークスペースにインストールしてね
  • Node.js の基礎知識

Building a chat bot

? コード サンプルの取得

このチュートリアル シリーズでは、プロジェクトのコードのホスティングと実行を簡略化するために、サードパーティのツール、Glitchを使用しています。

Glitch は、node.jsコードを記述して実行できるWebベースのIDEなので、少なくとも今のところ、localhostのトンネル、デプロイを気にすることなく、Teamsアプリ開発の概念と基本を学ぶことに集中できます。(Glitch はチュートリアルのために使っていますが、本来は開発に必要ありません。今後ゆくゆく Azure へのデプロイも含め、しっかりカバーしていきたいと思います。)

まず、この Glitch プロジェクトの remix ができるリンクをクリックしてください。リミックスとは GitHub で言うところのリポジトのをフォークのようなようなもので、自分用のプロジェクトのコピーが生成されるため、元のコードに影響なく自分用に好きなように変更できます。
Remix on Glitch
さて、自分専用プロジェクトのリポを取得すると、自動的に独自のWebサーバーURLを取得します。たとえば、生成されたプロジェクトは、3単語ほどでできたランダムな語で構成されています。たとえばそのプロジェクト名が achieved-diligent-bell だったら、ウェブサーバーのURLは https://achieved-diligent-bell.glitch.me になります。必要に応じて名前をカスタマイズすることもできます。
glitch project name

⚙️ App Configuration: App Studioを使ってアプリ マニフェストを作成

Teams 用のアプリを作成する場合は、Teams クライアントにインストールするアプリ パッケージを作成する必要があります。パッケージには以下が含まれます。

? your-app-package
    └── ? manifest.json
    └── ? color.png (192x192)
    └── ? outline.png (32x32)

残りの、アプリに必要なコードと画像などのアセットは、Web サーバーでホストする必要があります。(このチュートリアルでは、 Glitch からアプリを自動的にランするので特別なサーバの必要はありませんが、将来的に自分でアプリを作成する場合は用意してください。)
現時点ではマニフェスト ファイルを手動で作成するのではなく、App Studio というビジュアル ツールを使用してチーム クライアントに直接アプリ パッケージを作成、インストールできるようにします。

? Using App Studio

App Studio をまだインストールしていない方はインストール、すでにした場合は App Studio を開きます。

App Studio 上部の Manifest Editor(マニフェスト エディター) タブをクリックし、Create a new app(新しいアプリの作成)を選択します。

 App URLs セクションで、プライバシーと利用規約の Web ページ URL も入力します。この例では、プレースホルダ URL である、https://example.comを使用していますが、公開するアプリを開発する場合は、フェイクではない URL が必要になってきます。

そして Generate ボタンをクリックして App ID を生成してください。
bot-appstudio-01-details.png

? Configuring a bot

左側のメニューから、 Capabilities > Bots を選択

次に Set up をクリックして新しい bot を設定します。

Bot 名を入力し、ここでは Personal スコープを選択します。この個人用、パーソナル・ボットでは、bot と単一ユーザーの間で会話を行うことができます。 (スコープの詳細については、 Conversation basics 参照。)
bot-appstudio-02-new-bot.png
次に Generate new password ボタンをクリックします。ダイアログが開いたら、そこで表示されるパスワードをコピーしてください。次のステップに必要になります。
bot-appstudio-03-bot.png

? App credentials

ボット名の横にある ID (2cd53e8a-e698-4exx-... のような文字列) をコピーし、隠しファイルである.envファイルに環境変数として貼り付けます (.env-sample の名前を .env に変更します)。

App Passwordsの下で新規パスワードを生成し、それをコピーし、これも .env ファイルに貼り付けます。

これらの情報は、bot アダプターを初期化するために使用されます。(index.js を参照してください。

Messaging Endpoint で、bot サーバーを入力します。今回は、Glitch サーバ上でコードを動かしているので、 https://[your project].glitch.me/api/messages のように自分のプロジェクト名が入った URL がサーバとなります。

? App manifest package をインストール

Finish > Test and distribute へ行きます。

エラーが発生した場合は、それを修正してください、そうでなければ、Install をクリックしてクライアントにインストールしてください。
bot-appstudio-04-install.png
また、後でインストール、または配布するために、manifest.json と 2 つのアイコン画像を含む zip ファイルをダウンロードすることもできます。

チュートリアル通り、Glitch コード サンプルをリミックスしている場合は bot は既に動作するはずです。

でも bot を試す前に、これがどのようにコーディングされているかを簡単に説明してみましょう。

? Microsoft Bot Framework

マイクロソフト Bot Framework は、エンタープライズ・グレードの bot を構築できるオープンソース SDK です。

この SDK は、Teams だけでなく、Web やモバイル チャット、Skype、Facebook、Amazon Alexa、Slack、Twilio など、幅広い種類のチャット ボットで動作するように設計された強力なプラットフォームです。

? Initiating the bot service

まず、Glitch コードサンプルのリポジトリには、index.js、および bots.js に 2 つの JS ファイルがあります。

*注: Glitch は、事前定義された package.json からすべての依存モジュールを自動的にインポートするので、パッケージを手動でインストールする必要はありません。

index.js では、botbuilder ライブラリ、および HTTP サーバーと HTTP ルーティング要求を設定するためのライブラリを含める必要があります。ここでは私は Express を使用していますが、Restify など、他のものを使用することができます。

index.js:

// Import Express & set up HTTP server
const express = require('express');
const app = express();
const server = app.listen(process.env.PORT || 3978);

// Import bot services
const { BotFrameworkAdapter } = require('botbuilder');

// Bot's main dialog
const { ReverseBot } = require('./bot');

注: この例では、私は botbuilder のバージョン4.10.0を使用しています。コードが期待どおりに動作しない場合は、使用しているバージョンを確認してください!

次に、bot がユーザーと通信し、応答を送信できるようにするアダプターをセットアップします。

const adapter = new BotFrameworkAdapter({
  appId: process.env.MicrosoftAppId,
  appPassword: process.env.MicrosoftAppPassword
});

// Error handlings (See the Glitch sample for details!)

// Create the main dialog
const myBot = new ReverseBot();

? Bot ロジックへの要求の転送

Express を使用して、着信要求をリスニングするルーティングを処理します。

app.post('/api/messages', (req, res) => {
  adapter.processActivity(req, res, async context => {
    await myBot.run(context);
  });
});

前の手順で、 App Studio で URL を設定しました。/api/messages は、クライアント要求に応答するアプリケーションのエンドポイント URL です。

? 要求の処理とボットの返信の投稿

エンドポイントで要求を受信し、ボット ロジックに転送すると、アプリは要求のコンテキストを受け取り、bots.js でカスタム応答を作成します。

要求に対する適切なハンドラーを作成するために拡張された TeamsActivityHandler を参照してください。

const { TeamsActivityHandler, MessageFactory } = require('botbuilder');

class ReverseBot extends TeamsActivityHandler {
  constructor() {
    super();
    this.onMessage(async (context, next) => {
      const backward = [...context.activity.text].reverse().join(''); // reverse string
      const replyText = `? *${ backward }*`; // you can use markdown
      await context.sendActivity(MessageFactory.text(replyText));

      await next();
    });
  }
}

TeamsActivityHandler は、メッセージ イベント (*例えば onMembersAdded メソッドが会話にメンバーが追加されるたびに呼び出される) などのメッセージを処理し、返信を送信するチーム固有のクラスです。

例では、メッセージがクライアントに送信されると、onMessage がトリガーされ、メッセージ テキストを取得して、カスタム応答を作成するために使用できます。

?? Trying your bot

それでは、ボットを試してみましょう! Teams クライアントに移動し、左側のメニューバーからボットを起動するをクリックします。
すべてがちゃんと動作する場合は、次のように bot と会話できるはずです ??
bot-app-ja.png

この例では、テキスト返信を送信する方法のみを示しますが、ボタンやその他の UI コンポーネントを使用して、よりインタラクティブなメッセージを作成できます。これについては後で詳しく説明してゆきたいと思っています。

さて、チュートリアルを楽しんでいただけましたか?ぜひこれよりも良いユースケースを見つけて、素晴らしいアプリを作成することを願っています!

では、また次回 ?

?? この記事を英語で読みたいという方は dev.to のリンクからどうぞ!


? Learn more

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む