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

ApolloServerを使ってGraphQLのサブスクリプションを調査する

はじめに

GraphQLの概要の紹介、QueryとMutationの動きを確認した前回の続きです。
本記事はGraphQLのサブスクリプションについての投稿となります。

サブスクリプション(Subscription)とは直訳で「購読」という意味で、月額課金サービスなどの総称で耳馴染みのある言葉ですが、
GraphQLにおいては、Mutationにおいてデータ操作をした際に、クライアント側でサーバーから発行された変更情報を受け取ることを指し、チャットアプリや通知機能、ログイン認証などでの利用が考えられます。
こちらの解説が大変分かりやすいので、オススメです。

今回は前回サーバーを立てたExpress-GraphQLに代わりApolloを利用して、GraphQLサーバーを立てた上でサブスクリプションの動きを確認していきたいと思います。

Apolloとは

Apolloは、データグラフを構築するためのプラットフォームであり、アプリケーションクライアント(ReactやiOSアプリなど)をバックエンドサービスにシームレスに接続する通信レイヤーです。

クライアントとサーバーの中間にあるApolloサーバーによって、GraphQLによるデータのやり取りがスムーズになります。

アーキテクチャ例
download.png

公式ドキュメント

下準備

プロジェクトを作った後に、npm経由でapollo-serverをインストールします。

mkdir GraphQLPrac
cd GraphQLPrac
mkdir resolver
touch index.js db.js resolver/{Query.js,Mutation.js,Subscription.js}
npm init
npm install apollo-server --save

サンプルコードを読みやすくするために

PubSub

PubSubはサブスクリプションによる通知イベントを作成する工場のような存在。

example.js
const { PubSub } = require('apollo-server');

const pubsub = new PubSub();

gql

GraphQLのクエリを記述するために使用。クエリをApolloクライアントに渡すために推奨される方法。

example.js
const typeDefs = gql`
  type Subscription {
    postAdded: Post
  }

  type Query {
    posts: [Post]
  }

  type Mutation {
    addPost(author: String, comment: String): Post
  }

  type Post {
    author: String
    comment: String
  }
`

Resolver引数

リゾルバ関数には固定の役割を持つ4つの引数があります。

引数(昇順) 説明
parent フィールドの親(リゾルバーチェーン内の前のリゾルバー)のリゾルバーの戻り値。
args フィールドに提供されたすべてのGraphQL引数を含むオブジェクト
context 特定の操作のために実行されているすべてのリゾルバー間で共有されるオブジェクト
info フィールド名、ルートからフィールドへのパスなど、操作の実行状態に関する情報

コードの紹介と解説

作成したファイルにコードを書いていきます。
QueryとMutationについての概要は省略致しますので、はじめてGraphQLに触られる方はこちらの記事からどうぞ!?

先ず、データベース代わりのJavaScriptファイルを用意します。

db.js
const posts = [{
    id: '1',
    title: 'こころ',
    author: '夏目漱石'
}, {
    id: '2',
    title: '舞姫',
    author: '森鴎外'
}, {
    id: '3',
    title: '羅生門',
    author: '芥川龍之介'
}]

const db = {
    posts,
}

module.exports  = db;

続いてQuery,Mutation,そして今回のテーマであるSubscriptionについての処理をまとめたファイルを順番に用意していきます。

Query.js
const Query = {
    posts(parent, args, { db }, info) {
       //クエリを書いた時に引数が「ない」時
       //模擬データベースの内容を全て表示
        if (!args.query) {
            return db.posts
       //クエリを書いた時に引数が「ある」時
       //引数とtitle or authorが一致したものだけを表示
        }else{
            return db.posts.filter((post) => {
            const isTitleMatch = post.title.toLowerCase().includes(args.query.toLowerCase())
            const isAuthorMatch = post.author.toLowerCase().includes(args.query.toLowerCase())
            return isTitleMatch || isAuthorMatch
        })
    }
    }
}

module.exports  = Query

クエリに関する処理をまとめたファイルです。引数の有無で条件分岐をしています。
JavaScriptで条件を細かく書くことで、「本当に必要な情報だけを取得できること」がGraphQLの強みです。

Mutation.js
const Mutation = {
    createPost(parent, args, { db, pubsub }, info) {
        const postNumTotal = String(db.posts.length + 1)
        const post = {
            id: postNumTotal,
            ...args.data
        }

        //データベース更新
        db.posts.push(post)
        //サブスクリプション着火
        pubsub.publish('post', { 
                post: {
                    mutation: 'CREATED',
                    data: post
                }
             })
        return post
    },
    updatePost(parent, args, { db, pubsub }, info) {
        const { id, data } = args
        const post = db.posts.find((post) => post.id === id)
        if (!post) {
            throw new Error('Post not found')
        }

        if (typeof data.title === 'string' && typeof data.author === 'string') {
            //データベース更新
            post.title = data.title
            post.author = data.author
            console.log(post)
            //サブスクリプション着火
            pubsub.publish('post', {
            post: {
                mutation: 'UPDATED',
                data: post
            }
        })
        }

        return post
    },
    deletePost(parent, args, { db, pubsub }, info) {
        const post = db.posts.find((post) => post.id === args.id)
        const postIndex = db.posts.findIndex((post) => post.id === args.id)

        if (postIndex === -1) {
            throw new Error('Post not found')
        }
        //データベース更新
        db.posts.splice(postIndex, 1)
        //サブスクリプション着火
        pubsub.publish('post', {
                post: {
                    mutation: 'DELETED',
                    data: post
                }
            })
        return post
    },
}

module.exports  = Mutation

ミューテーションの処理内でデータベースの更新とサブスクリプションの着火をしています。

Subscription.js
const Subscription = {
    post: {
        subscribe(parent, args, { pubsub }, info) {
            return pubsub.asyncIterator('post')
        }
    }
}

module.exports = Subscription

サブスクリプションのファイルです。
pubsub.asyncIteratorでサブスクリプションのイベントを非同期でリッスンします。

説明の関係で最後になりましたが、
スキーマの定義とサーバー起動のファイルになります。

index.js
const  {ApolloServer,PubSub,gql} = require('apollo-server');
const db = require('./db')
const Query = require('./resolver/Query')
const Mutation = require('./resolver/Mutation')
const Subscription = require('./resolver/Subscription')

//スキーマ定義
const typeDefs = gql`
type Query {
  posts(query: String): [Post!]!
}

type Mutation {
  createPost(data: CreatePostInput!): Post!
  deletePost(id: ID!): Post!
  updatePost(id: ID!, data: UpdatePostInput!): Post!
}

# サブスクリプション
type Subscription {
  post: PostSubscriptionPayload!
}

input CreatePostInput {
  title: String!
  author: String!
}

input UpdatePostInput {
  title: String
  author: String!
}

type Post {
  id: ID!
  title: String!
  author: String!
}

######################
# サブスクリプションで利用
######################

# enum型でMutation.js内のサブスクリプション着火と連動
enum MutationType {
  CREATED
  UPDATED
  DELETED
}

# サブスクリプションのフィールド
type PostSubscriptionPayload {
  mutation: MutationType!
  data: Post!
}

`
//PubSubのインスタンスを作成,サブスクリプションが利用可能に!
const pubsub = new PubSub()

const server = new ApolloServer({
    typeDefs: typeDefs,
    resolvers: {
        Query,
        Mutation,
        Subscription,
    },
    context: {
        db,
        pubsub
    }
})

server.listen().then(({ url, subscriptionsUrl }) => {
    console.log(`? Server ready at ${url}`);
    console.log(`? Subscriptions ready at ${subscriptionsUrl}`);
  });

サーバーを立てる際にスキーマやリゾルバ、PubSubなどを引数に指定しています。
指定した引数はクエリやミューテーションそしてサブスクリプション、それぞれの処理で利用をしています。

準備が出来たらターミナルから起動させます。

node index.js
? Server ready at http://localhost:4000/
? Subscriptions ready at ws://localhost:4000/graphql

前回同様にGraphQL IDEにてテストをしてみます。

サブスクププションを利用するには、クエリを書いた後にYouTubeの再生ボタンのような矢印をクリックします。
写真のように赤いポーズボタンに変化したら、サブスクリプションの起動成功です。

スクリーンショット 2020-10-15 23.00.31.png

先ずはミューテーションで新しくデータを作ってみます。
スクリーンショット 2020-10-15 23.00.52.png

そのままサブスクリプションのタブに移動して、結果を確認します。
スクリーンショット 2020-10-15 23.01.03.png
Apolloサーバーからデータが新しく作成されたことに対する変更情報を受け取ることが出来ました。

データの更新、そして削除についても確認します。

ミューテーションによるデータの更新。
スクリーンショット 2020-10-15 23.01.53.png

サブスクリプションにてデータの更新の確認。
スクリーンショット 2020-10-15 23.01.59.png

ミューテーションによるデータの削除。
スクリーンショット 2020-10-15 23.02.11.png

サブスクリプションにてデータの削除の確認(更新と削除を連続して行っています)

スクリーンショット 2020-10-15 23.02.24.png

以上、ミューテーションによるデータの更新をサブスクリプションを通して確認することが出来ました!!??

おわりに

クエリやミューテーションと比較してサブスクリプションは理解に時間がかかったものの、
実際にコードを書き、GraphQL IDEでテストをすることによって自分の中で腹落ちさせることが出来ました。
次回の記事ではフロントにVueを使った上で、実際のアプリケーションの中でGraphQLを使っていきます!

それでは、また!?

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

javascriptのLocalStorage を使ってお気に入り機能を自作してみた ②実装編-基盤作り-

どうも7noteです。プラグインより多機能なお気に入り機能を作成。前回の続き

①準備編がまだの方はこちら

今回作るお気に入り機能の特徴

  • JSON形式にして配列のまま保存。呼び出す時もJSONから普通の配列に戻して使用
  • 重複登録ができないように処理する
  • wordpressと絡める場合はphpの知識も多少必要

今回のメインソース

メイン基盤となるプログラムを書いていきます。
完成予定図は以下の通り。

完成予定図.js
/*お気に入りに追加機能*/
function addfav(oid){

    var key = 'お気に入りID';                                   

    var getjson = localStorage.getItem(key);
    var oidlist = JSON.parse(getjson);
    if(oidlist == null){
        oidary = new Array(oid);
        var setjson = JSON.stringify(oidary);
        localStorage.setItem(key, setjson);
    } else {
        if(oidlist.indexOf(oid) == -1){
            oidlist.push(oid);
            var setjson = JSON.stringify(oidlist);
            localStorage.setItem(key, setjson);
        }
    }
}

/*お気に入りから削除機能*/
function removefav(oid){

    var key = 'お気に入りID';

    var getjson = localStorage.getItem(key);
    var oidlist = JSON.parse(getjson);
    if(oidlist != null){
        var checkitem = oidlist.indexOf(oid);
        if(checkitem != -1){
            oidlist.splice( checkitem, 1 );
            var setjson = JSON.stringify(oidlist);
            localStorage.setItem(key, setjson);
        }
    }
}

※このソースだけでは何も動きません。これは関数なのでどこかで実行させないと動かない!

それではさっそく解説しながら一から書いていきたいと思います。

1.とりあえずLocalStorageを使ってみる。

script.js
var key = 'お気に入りID';                 /* keyの名前を決める。日本語もOK。 */
var oidary = new Array("No:20");        /* 値を決める。あとで複数の値を保持する予定なので配列形式に。 */
var setjson = JSON.stringify(oidary);   /* JSON形式に変換 */
localStorage.setItem(key, setjson);     /* ローカルストレージにデータを格納 */

上のスクリプトを動かすと、ブラウザのローカルストレージにデータを格納できます。
このスクリプトの場合、以下のようなデータが保管されます。

キー → お気に入りID
値  → No:20

実際に格納されているデータを見るには以下の手順で確認できます。

→「F12キーで検証ツールを開く」
→「Applicationタブを選択」
→「Storage欄のLocal Storageをクリック」
→「【file://】をクリック」
→KeyとValueにそれぞれ値が格納されています

実際の画面がこちら↓
f12.png

このようにしてデータを格納することができます。

2.LocalStorageから値を取得

次に格納された値を取得する方法

script.js
var key = 'お気に入りID';                  /* 取得するキーを指定 */
var getjson = localStorage.getItem(key); /* ローカルストレージから値を取得 */
var oidlist = JSON.parse(getjson);       /* 取得したデータがJSON形式から元に戻す */

console.log(oidlist); /* デバッグ用 */

localStorage.getItem()で特定のキーの値を取得することができます。
JSON形式で保存しているので、元の形式に戻すために、JSON.parse()をします。

3.LocalStorageから値を削除

特定の値のみ削除するには、一度値を取得してjavascriptで配列から削除する必要があります。

script.js
  var key = 'お気に入りID';                   /* 取得するキーを指定 */
  var oid = 'No:25';                        /* 取得するキーを指定 */
  var getjson = localStorage.getItem(key);  /* ローカルストレージから値を取得 */
  var oidlist = JSON.parse(getjson);        /* 取得したデータがJSON形式から元に戻す */
  var checkitem = oidlist.indexOf(oid);     /* 削除する値の配列番号を確認 */
  if(oidlist.indexOf(oid) != -1){           /* 値が存在するか確認 */
    oidlist.splice( checkitem, 1 );         /* 指定の値を削除 */
    var setjson = JSON.stringify(oidlist);  /* JSON形式に変換 */
    localStorage.setItem(key, setjson);     /* ローカルストレージにデータを格納 */
  }

ローカルストレージには、値を削除するStorage.removeItem()がありますが、これは値をすべて削除してしまうため、お気に入り登録した他のものまで削除してしまいます。


Storage.removeItem()をつかってしまった例
「No:20とNo:33をお気に入りしてました。」
「No:20をお気に入りから削除しようとしました。」

理想

{お気に入りID: "No:20", "No:33"}
↓(削除後)
{お気に入りID: "No:33"}

現実

{お気に入りID: "No:20", "No:33"}
↓(削除後)
{お気に入りID: }


JSON形式で値を格納しているため、一部の値のみ削除するには一度取り出す必要があるのです。
上記のプログラムでは、本当にその値があるかどうかを確認してから消すようにしています。

4.LocalStorageに値を追加する時の処理を見直す

ローカルストレージの特徴として、1つのキーには1つの値しかいれることができません。
そのため、同じキーにデータを入れると上書きされてしまいます。

上の1.2.3.で書いたスクリプトを単純にそのまま使っても、No:20をすでにお気に入りしていたとして、No:33を新しくお気に入りに追加すると、元のNo:20が消えてしまいます。

そこで、値の一部を削除する時同様に、一度データを取得してから配列に値を追加するやり方でデータを格納する必要があります。

script.js
var key = 'お気に入りID';                  /* 取得するキーを指定 */
var oid = "No:33";                       /* 格納するキーを指定 */
var getjson = localStorage.getItem(key); /* ローカルストレージから値を取得 */
var oidlist = JSON.parse(getjson);       /* 取得したデータがJSON形式から元に戻す */
if(oidlist.indexOf(oid) == -1){          /* 重複していないか確認 */
  oidlist.push(oid);                     /* 配列に値を追加 */
  var setjson = JSON.stringify(oidlist); /* JSON形式に変換 */
  localStorage.setItem(key, setjson);    /* ローカルストレージにデータを格納 */
}

※ローカルストレージにお気に入りIDというキーが存在しないまま動かすと、値(配列)が取得できずにエラーになります。1.の手順を事前に行うなどしてキーを作成してください。
検証ツール上で手動で追加することもできます。(ダブルクリック or 右クリックからの[Add new])

これで基礎的な処理はすべて書くことができました。
では実運用レベルまで持っていきましょう。

次の章が最後になります!!

(※続きの記事はただいま執筆中!明日公開できるようがんばります 汗)

前回(①準備編)の記事はこちら

おそまつ!

~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ

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

Javascript JSONとは

JSONとは

オブジェクト型式のデータフォーマットで、オブジェクトの形を保持し、通信が軽量なテキストデータでもあるのがこのJSONです。
Javascriptで他言語との連携やサーバーサイドにデータを送る際に使用することが多いです。
オブジェクトと非常に似てますが、JSONは文字列型のデータです。

JSONとXML

データフォーマットには、JSONやXMLがありますがXMLはHTMLの構造に似ていますが、直感的に構造が分かりにくいです。対してJSONはオブジェクト型式のため、分かりやすく値の取り出し方も簡単です。

JSON.stringify()

オブジェクト型式からJSON型式へ変換する。
JSON.stringify()の引数に変換したいオブジェクトを渡すとJSON型式に変換します。

const obj = { foo: "foo", hoge: "hoge" }
const json = JSON.stringify(obj)
console.log(json, typeof json)

// {"foo":"foo","hoge":"hoge"} stringと出力されます。

以上のことからJSONが文字列であることがわかります。
※JSONのメンバーは必ず、""(ダブルクウォーテーション)を使用しなくてはなりません。

JSON.parse()

JSONをオブジェクトとして扱うためにはparseメソッドを用いて変換しなくてはなりません。
JSON.parse()の引数に変換したいJSONを渡すとオブジェクトに変換します。

const obj = { foo: "foo", baz: "baz", hoge: "hoge"}
const json = JSON.stringify(obj)
// JSON型式へ

console.log(JSON.parse(json))
//オブジェクト型式へ
//{foo: "foo", baz: "baz", hoge: "hoge"}

JSONで扱えるデータについて

・文字列(string)
・数値(number)
・真偽値(boolean)
・nul
・配列値(array)
・オブジェクト値(object)

上記データを扱うことができるので、複雑なデータ構造も対応可能です。

まとめ

現在ではデータフォーマットはJSONが主流となってます。そのためJSONを使っていきましょう!

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

Symbol-SDKなしで着金イベント発火方法

はじめに

初学者向けに分かりやすく書いています。
Symbol-SDKを使わずにjavaScriptのWebSocketのみで着金イベントを実装する方法です。

SDKが不要なので環境を気にせずjavascriptだけで実装できます。
気軽にトリガーとして組むことができます。

symbol-node.v 0.10.x
javaScript
html

webSocketの準備

今回はopening-lineさんのHTTPSノードに接続してみます。

https://sym-test.opening-line.jp:3001

websocket用のURLに変換します。

wss://sym-test.opening-line.jp:3001/ws

上記のURLでwebSocketのインスタンスを作成する

ws = new WebSocket('wss://sym-test.opening-line.jp:3001/ws');

websocketオブジェクトが作成された瞬間に接続開始されます。

websocketの接続確認

無事にwebsocketが接続されるとsymbolノードから
UID(ユニークなID)が返ってきます。

{"uid":"4T5S5WHA5WMO5M6CDPEY6TDWLM3OLETX"}

こういったJsonオブジェクトです。
ちゃんとUIDを受けっとっているか確認していきます

始めに正しく接続できたか調べます。
onopenは接続したときに発火するイベントです。

ws.onopen = function (e) {ここに接続したときのイベントを書く}

このようにコンソールに分かりやすく書いておきます。

ws.onopen = function (e) {
  console.log("接続成功");
}

実行してみるとコンソールにちゃんと表示されています。
1.png

UIDの確認

次にSymbolノードからUIDがメッセージに返ってきているはずなので確認します。

onmessageはメッセージを受信したときに発火するイベントです。

ws.onmessage = function (event) {ここにイベントを書く}

event.dataに受信したメッセージが格納されています。
メッセージはJSONデータなので配列に変換します。

response = JSON.parse(event.data);

受信したデータをコンソールに表示します。

console.log(response)

こんな感じです。

ws.onmessage = function (event) {
    response = JSON.parse(event.data);
    console.log(response)
}

実行してみるとちゃんとUIDを取得できました。
2.png

以上でSymbolから着金データをもらう準備ができました。

UIDを付けてリクエストを送り返す

symbolからデータを受け取るにはUIDを付けてリクエストする必要があります。
※UIDは接続する度に変わります。
色々データを受け取れるのですが公式

最初に基本のブロック情報をリクエストしてみましょう。

受信したメッセージ(response)からUIDを取り出します。

uid=response.uid;

毎回UIDがあるわけではないので初回のみ送られてくるUIDとそれ以降のデータとを分ける処理をします。

 if('uid' in response){
    ここにUIDがあるときの処理
     }

UIDがあるときにuidにUIDを格納します。

 if('uid' in response){ 
  uid=response.uid;
}

さらにUIDがあるときに送り返すメッセージをbodyに作成しておきます。

 body = '{"uid":"' + uid +'","subscribe":"block"}';

"uid"に取得したUIDを"subscribe"に受信するトピック名を
今回はブロックを受信したいので"block"にします。
bodyを追加してこのようになります。

 if('uid' in response){   
     uid=response.uid;
     body = '{"uid":"' + uid +'","subscribe":"block"}';
   }

これでUIDを取得して送り返すメッセージが作成できました。
あとはこのbodyをwebSocket.send()でSymbolノードに送信すれば受信できるようになります。

send(ここに送り返すメッセージ);

UIDを受け取り、送り返すメッセージを作成して送信します。

 if('uid' in response){   
     uid=response.uid;
     body = '{"uid":"' + uid +'","subscribe":"block"}';
     ws.send(body);
   }

3.png

実行してみると15秒に一回ブロック通知が送られてきます。
あとはbodyの"subscribe"の内容を変えることで色々取得できます。
subscribeの種類

承認済みのTransactionを受信する

では先ほどのスクリプトを利用して認証済みTransactionを受信するスクリプトを作成します。

変更点はbodyの"subscribe"の内容を変えるだけです。
ただし1分間なにも受信しないと接続が切れてしまうので、
"block"は受信したままで追加で承認済みTransactionを受信させます。
新たにtransactionという変数にリクエストメッセージを作成します。

transaction= '{"uid":"'+uid+'","subscribe":"confirmedAdded/ここに監視するアドレスを入力"}'

承認済みは"confirmedAdded/+アドレス"
未承認は "unconfirmedAdded/+アドレス"
です。
未承認はすぐに流れてきます。
承認済みは承認まで時間がかかります。

アドレスをいれてこんな感じになります。
例:
TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ

{"uid":"'+uid+'","subscribe":"confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"}

送信するメッセージができたので

send()

に作成したtransactionを入れてsymbolノードに送信します。
これで指定しアドレスに承認済みの着金があれば受信することができます。

 if('uid' in response){   
     uid=response.uid;
     body = '{"uid":"' + uid +'","subscribe":"block"}';
     ws.send(body);
   ws.send(transaction);
   }

実行して先ほど指定したアドレスに送金してみると。
ちゃんと受信されています。
4.png

着金の時だけ発火するイベントを作る

送られてきたデータのresponse.topicの中にsubscribeの種類が入っているので、
抜き出して条件式にいれ着金(承認済Transaction)の時だけ発火させます。

先ほど送信したsubscribe:の
"confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"

とtopicが同じだったら発火させます。
こうなりますね。

   if(response.topic =="confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ")
if('uid' in response){
        uid=response.uid;
        body = '{"uid":"' + uid +'","subscribe":"block"}';
        transaction= '{"uid":"'+uid+'","subscribe":"confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"}'
        ws.send(body);
        ws.send(transaction);
}

if(response.topic=="confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ")
//ここでsymbol-SDKなしで着金イベントが発火します。

}

これで完成です。
あとは中にちゃんと動くか

console.log('ここに着金の時だけ発火するイベントを書く');

を中に書いて実行してみます。

if('uid' in response){
        uid=response.uid;
        body = '{"uid":"' + uid +'","subscribe":"block"}';
        transaction= '{"uid":"'+uid+'","subscribe":"confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"}'
        ws.send(body);
        ws.send(transaction);
}
if(response.topic=="confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"){
     console.log('ここに着金の時だけ発火するイベントを書く');
}

実行して指定したアドレスに送金してみます。承認されるまで少し待ちます。

5.png

正しく着金イベントで発火するスクリプトが完成しました。

if(response.topic=="confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"){
     //この中のプログラムが実行されます。
}

全体としてはこんな感じです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Symbol-websocket_test</title>
</head>
<body>

  <script>
    ws = new WebSocket('wss://sym-test.opening-line.jp:3001/ws');
    ws.onopen = function (e) {
        console.log("接続成功");
        }

    ws.onmessage=function(event){
        response=JSON.parse(event.data);
        console.log(response);
        if('uid' in response){ 
        uid=response.uid;

        body = '{"uid":"' + uid +'","subscribe":"block"}';
        transaction= '{"uid":"'+uid+'","subscribe":"confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"}'
        ws.send(body);
        ws.send(transaction);
        console.log(response.topic);
       }

    if(response.topic =="confirmedAdded/TALST5SKMUOJ64ODZABQXJPJLI4XCQI5AU4NDPQ"){
        console.log("ここに着金の時だけ発火するイベントを書く");

        }
   }
    </script>

</body>
</html>

以上で完成です。

最後に

このようにハイテク技術のブロックチェーンで有りながら、SymbolはSDKを使うことなく容易にTransactionの有無をリアルタイムで受信することができます。

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

Node.jsとはなにか?なぜみんな使っているのか?

この記事は

「JavaScriptの勉強してたらみんなNode.jsの存在を前提に話が進む。でもNode.jsってWebサーバじゃないの? なんでインストールしなきゃいけないの? なんでみんな使ってるの?」

といった疑問を解消することを目的としています。

大前提:JavaScriptの特徴

Node.jsを説明する前にJavaScriptと他のプログラミング言語の違いを知っておく必要があるので説明します。

JavaScriptはChromeやFirefoxといった「ブラウザ上」で動作するプログラミング言語です。
対してPythonRubyのような一般的なプログラミング言語は通常「パソコン上」で動作します。1

このことが生み出す違いは、OSの機能にアクセスできるかどうかです。
「OSの機能」とは例えばファイルの読み書きや、USB接続された周辺機器へのアクセス、ネットワーク通信などの機能のことです。2
パソコン上で動作するアプリケーション(PythonやRubyなどを含む)ではこれらの機能を扱うことができます。3

(図だとPythonだから自由にアクセスできるみたいにも見えますが、パソコン上で動作するアプリケーションだから自由にアクセスできるという方が正しいですね)

それに対し、ブラウザ上で動作するプログラム(JavaScript)がOSの機能へアクセスできてしまうと大変まずいことになります。4
あるサイトにアクセスしただけで勝手にパソコン上のファイルを読み書きされたり、プログラムのミスでうっかりパソコン上のファイルを一部消されたりしたら大問題ですよね。5

ということで、ブラウザ上で動作するJavaScriptはOSの機能にアクセスできないようになっています。
ですがOSの機能へ全くアクセスができないということは、ローカルファイルの読み込みや保存ができないのはもちろん、ユーザーがどこをクリックしたのか、キーボードのどのキーを押したのかも分からないという状態になります。それでは不便なのでブラウザが限定的にOSの機能へのアクセスを仲介してくれています。6
最近ではカメラやマイクへのアクセスの仲介もやってくれるので、ブラウザ上でWeb会議できたりしますよね。

Node.jsって何者?

そんなブラウザ上という制限された環境でしか動けなかったJavaScriptを、PythonやRubyのようにパソコン上で動かせるようにしてくれるのが「Node.js」です。

誤解されることが多いのですが、Node.jsはWebサーバでもなければRailsやDjangoのようなWebフレームワークでもありません。JavaScript実行環境です。

WindowsにPythonをインストールすると「python.exe」ができるように、Node.jsをインストールすると「node.exe」ができます。
python.exeがPythonコードを実行するアプリケーションであるように、node.exeはJavaScriptコードを実行するアプリケーション(つまりJavaScript実行環境)です。

さて、冒頭からここまで「ブラウザ上」と「パソコン上」という表現を何回か出しましたが、これをかっこよく言いかえたのが「クライアントサイド」と「サーバサイド」です。

Node.jsはよく「サーバサイドのJavaScript実行環境」と紹介されます。
よく誤解されますが、この「サーバ」というのは「Webサーバ」のことではなく「パソコン」のことです。7
サーバサイドのJavaScript実行環境パソコン上でJavaScriptを実行する環境 ということです。

つまりNode.jsは(ブラウザ上ではなく)パソコン上でJavaScriptを動かすための環境であるといえます。

Node.jsではJavaScriptでOSの機能にアクセスするプログラムを組むことができます。
つまりブラウザ上で動作していたときはできなかった自由なファイルの読み書きなどができるようになります。

結果的にPythonやRubyなどと同じようにWebサーバやWebアプリケーションを作成することもできますが、Node.jsはWebサーバやWebアプリケーションのためだけのものではないということは覚えておいてください。

npmって何者?

ちょっと話はそれますが一応npmのことも解説しておきます。

npmはNode.jsのパッケージ管理ツールです。
Pythonにおけるpip、Rubyにおけるgem(RubyGems)、Debianにおけるapt、MacにおけるHomebrew、Rustにおけるcargo。だいたいそんな感じです。

たまにyarnというのが出てきますがnpmと同じことができる物だと思って大丈夫です。

「パッケージ」というのはライブラリやフレームワークのことです。
つまりVueやReact, webpack, jQueryなどのことです。

Node.jsで使いたいライブラリがある場合、jsファイルをダウンロードしてきて<script src="xxx.js"></script>って書いて……とかはせずにnpmを使ってインストールします。

Node.jsってなんでみんな使ってるの?

Node.jsによって枷を外されたJavaScriptは色々なことができるようになりました。
その用途は多種多様ですが、現在、Node.jsを使っている人の目的のほとんどは以下の4つに分類できます。(筆者の主観的な意見です)

  1. 新しい仕様のJavaScriptまたはTypeScriptでクライアントサイドのプログラムを書きたい。
  2. Webサーバを作りたい。
  3. Webアプリケーションを作りたい。
  4. モバイル/デスクトップ用のアプリケーションを作りたい。

目的1. 新しい仕様のJavaScriptまたはTypeScriptでクライアントサイドのプログラムを書きたい

おそらくNode.jsを使っている人の目的としてはこれが一番多いです。

新しい仕様(ES2015以降)のJavaScriptについては至る所で解説されているのでここでは簡潔に。TypeScriptについては割愛します。

JavaScriptは年々仕様が更新され、どんどん新しい機能が増えています。特にES2015というバージョンではそれまでにはなかった便利な機能がたくさん仲間入りしました。
しかしJavaScriptの仕様を新しくしても既存のブラウザが追いついてこれないという問題が発生します。
これを解決するために登場したのが「新しい仕様で書いたJavaScriptファイル」を機械的に「旧仕様(ES5)のJavaScriptファイル」に変換してしまう手法です。

この変換を行うツール(トランスコンパイラ)の現在の主流がBabelであり、それを動かすための環境として現在よく選ばれているのがNode.jsです。

つまりかなり乱暴な言い方をすると

みんなconstimportなどを使ってクライアントサイドのJSを書きたい

でも古いブラウザは対応していない

Babelを使えば新しい仕様で書いても古いブラウザに対応したJSファイルに変換できる

BabelはNode.js上で動かすことができる

みんなNode.jsを使って開発するようになる

ということです。

目的2. Webサーバを作りたい

Node.jsの登場でJavaScriptでWebサーバを構築できるようになったので話題になりました。
元々Node.jsはスケーラブルなネットワークアプリケーション(大量の同時接続をさばけるWebサーバ)の構築を目的として設計されました。
つまりApachenginxのようなWebサーバをNode.jsを利用して作れるということです。

実際にはNode.jsのみで企業などの運用に耐えうるWebサーバを構築するのは難しいので、その前段にApacheやnginxをリバースプロキシとして置く構成が多いようです。

目的3. Webアプリケーションを作りたい

Ruby + RailsやPython + Djangoなどで作るようなWebアプリケーションをNode.jsで作ることも可能です。

わかりやすくするためにこの場合に対応する項目を表で書くと

実行環境 言語 Webフレームワーク
Ruby Ruby Ruby on Railsなど
Python Python Djangoなど
Node.js JavaScript Express.jsなど

となります。

フロントエンドしかやったことがない人がサーバサイドも書くことになったときにJavaScriptしかできないからNode.jsを選ぶなんて言われたりしますが、正直Node.js+Express.jsを勉強する労力と、Ruby+RailsやPython+Djangoの勉強をする労力はあまり変わらないと思いますので、言語にとらわれずにそれぞれの特徴をよく調べてから選択するのがいいかと思います。

目的4. モバイル/デスクトップ用のアプリケーションを作りたい

Node.jsではモバイルアプリケーションデスクトップアプリケーションの開発ができます。
フレームワークはモバイルアプリケーションであればReact Nativeが、デスクトップアプリケーションであればElectronが使われることが多いです。

React Nativeは使ったことがなく知識も少ないので、以下Electronのみについて説明します。悪しからず。

ElectronJavaScript+HTML+CSSを使用してデスクトップアプリケーションを作成するためのフレームワークです。

JavaScriptは元々ウェブサイト用の言語ですのでUIの操作に使われることが多く、そういったライブラリやフレームワークは洗練され、成熟しています。その財産を利用してWebサイトと同じようにUIが構築できるというのは大きなメリットになります。

また、Electronでは同じコードでWindows/Mac/Linuxのアプリが作成(クロスプラットフォーム開発)できます。

Visual Studio CodeSlackDiscordTwitchSkypeといったデスクトップアプリがこのElectronでできています。

目的5. その他

他にもウェブサイトのアセットをバンドル(webpack)するためにNode.jsを使ったり、SassをCSSに変換(node-sass)するためにNode.jsを使ったり、テストツール(Jest)やコード検証ツール(ESLint)を使うためにNode.jsを使ったり、開発用の簡易Webサーバ(webpack-dev-server)をローカルで立てるためにNode.jsを使ったり、静的サイトをビルド(Gatsby)するためにNode.jsを使ったりと、Node.jsは様々な用途で使われています。

最後に

Node.jsは他のプログラミング言語と同じような大きな可能性をJavaScriptにもたらしてくれました。(話が複雑になるので本文中では言及を避けましたがV8 JavaScriptエンジンのおかげでもあります)

ちまたで言われるように、たしかにJavaScriptは(その出自のせいもあり)他の言語に比べて設計が甘い部分もあります。それで同じ土俵に立たれてもなあ……という意見もわかります。
ですがこんなに若い層の使用人口が多く、ライブラリなども含めて物凄い勢いで進化していき、トレンドが走馬灯のように移り変わるプログラミング言語は他にありません。
jQueryなんてもはや歴史的遺物みたいな扱いになっていますが、誕生したのはRailsやDjangoより後ですからね。物凄いスピード感です。
この時代に生まれ、このスリリングなJavaScriptの進化の波に乗れるのはワクワクできて楽しいことだと個人的には思います。

最後に、冒頭でも言いましたが、この記事で「Node.jsってWebサーバじゃないの?ES2015で書きたいだけなのになんでインストールしなきゃいけないの?」みたいなよくある疑問が解消できたら幸いです。


  1. 「JavaScriptはブラウザ上で動作してる。つまりパソコン上のブラウザ上で動作してるってことだから……結局パソコン上で動作してるのでは?」と思ってしまった方は、本文中の「パソコン上で動作」を「パソコン(OS)上で直接動作」と読み替えて読んでください。 

  2. パソコンが行える全ての機能といってもいいです。 

  3. 昨今ではOSのセキュリティがしっかりしているのでインストールしたアプリケーションであっても自由に全てのOSの機能を使えるわけではなく、アプリケーションが特定の機能にアクセスしようとしてきたら、ユーザーに「これ本当に大丈夫?」と許可を求めることが多いです。 

  4. ActiveXとかいうのはこれができちゃいますが。 

  5. JavaScriptは関係ないですけど実際昔HDDバースト事件なんてのがありました。 

  6. ブラウザはインストールされたアプリケーションなので当然OSの機能へアクセスできます 

  7. 正確には「何らかのサーバ機能を稼働させているコンピュータ」のことです(サーバ機能を稼働させていればパソコンも含まれます。もちろんサーバ専用機なども含まれます) 

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

React Hooksの強制再レンダリング方法

React Hooksでの強制サイレンダリング方法

クラスコンポーネントでは、

this.focusUpdate()

が使えましたが、関数コンポーネントではそうは行きませんよね。
「形が不細工でもレンダーしたい!」という方にお勧めなのがこちらの方法です。

//boolean型のstateを作成
const [update,setUpdata]=useState<boolean>(false)
//レンダリングしたい場所でこれを差し込むだけ
setUpdata(update?false:true)

setUpdata(update?false:true)の役割は、updateステートがtrueだった場合"false"、falseだった場合"true"にするだけです。
ぜひ使っていきましょう。

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

プログラミングコードを販売できるサービス「Code-sell」をリリースした(個人開発)

初めに

今回、約2か月ぶりにwebアプリを公開しました。
プログラミングコードを販売できるサービス Code-sellです。

https://www.code-sell.net/

なるべく気軽に販売・購入できるように工夫しました。
100円から価格設定できます。
ちなみに僕が今まで作ってきた4つのwebアプリのコードをすべて無料で公開しています!
ほしい人いるかわからないけど何かの参考にでも...。

code-sell.png

↑topページ

なぜ作ったか

今まで作ったwebアプリを販売(譲渡)しようと思ったのですが権利の問題や面会などめんどくさそうなものがたくさん出てきました。そんな時に思いつきました。Code-sellは譲渡はせずコードをダウンロードするだけなので権利の問題も考えなくていいですし、面会ももちろんありません。

できること

google認証
stripeを使った、購入、送金
いいね
通知
言語タグ・説明タグ

とかです。基本的な機能しかいまはありません...。

使った技術

rails6
ruby2.7
stripe
postgresql
slim
ridgepole
JavaScript

くらいですかね。
このなかでもstripeには本当に苦労しました。
情報はあるんですがどれもこれもコードの説明?で実践的な情報が本当に少ないです。
なので組み立てるのにかなり時間をかけました。
絶対にstripeに関する記事を出すと約束します。

終わりに

読んでくれてありがとうございました。ぜひcode-sell使ってみてください!
https://www.code-sell.net/

※まだ公開したばかりなので不具合を見つけたらお問い合わせフォームやらQiitaのコメントなどで教えてください。お願いします。

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

コードを販売できるサービス「Code-sell」をリリースした(個人開発)

初めに

今回、約2か月ぶりにwebアプリを公開しました。
プログラミングコードを販売できるサービス Code-sellです。

https://www.code-sell.net/

なるべく気軽に販売・購入できるように工夫しました。
100円から価格設定できます。
ちなみに僕が今まで作ってきた4つのwebアプリのコードをすべて無料で公開しています!
ほしい人いるかわからないけど何かの参考にでも...。

code-sell.png

↑topページ

なぜ作ったか

今まで作ったwebアプリを販売(譲渡)しようと思ったのですが権利の問題や面会などめんどくさそうなものがたくさん出てきました。そんな時に思いつきました。Code-sellは譲渡はせずコードをダウンロードするだけなので権利の問題も考えなくていいですし、面会ももちろんありません。

できること

google認証
stripeを使った、購入、送金
いいね
通知
言語タグ・説明タグ

とかです。基本的な機能しかいまはありません...。

使った技術

rails6
ruby2.7
stripe
postgresql
slim
ridgepole
JavaScript

くらいですかね。
このなかでもstripeには本当に苦労しました。
情報はあるんですがどれもこれもコードの説明?で実践的な情報が本当に少ないです。
なので組み立てるのにかなり時間をかけました。
絶対にstripeに関する記事を出すと約束します。

終わりに

読んでくれてありがとうございました。ぜひcode-sell使ってみてください!
https://www.code-sell.net/

※まだ公開したばかりなので不具合を見つけたらお問い合わせフォームやらQiitaのコメントなどで教えてください。お願いします。

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

コードを販売できるサービス「Code-sell」をリリースした!(個人開発)

追記
メール認証のエラーを修正しました。
いままで気づけなくてすみませんでした。

初めに

今回、約2か月ぶりにwebアプリを公開しました。
プログラミングコードを販売できるサービス Code-sellです。

https://www.code-sell.net/

なるべく気軽に販売・購入できるように工夫しました。
100円から価格設定できます。
ちなみに僕が今まで作ってきた4つのwebアプリのコードをすべて無料で公開しています!
(今非公開にしています。すみません。)
ほしい人いるかわからないけど何かの参考にでも...。

code-sell.png

↑topページ

なぜ作ったか

今まで作ったwebアプリを販売(譲渡)しようと思ったのですが権利の問題や面会などめんどくさそうなものがたくさん出てきました。そんな時に思いつきました。Code-sellは譲渡はせずコードをダウンロードするだけなので権利の問題も考えなくていいですし、面会ももちろんありません。

できること

google認証
stripeを使った、購入、送金
いいね
通知
言語タグ・説明タグ

とかです。基本的な機能しかいまはありません...。

使った技術

rails6
ruby2.7
stripe
postgresql
slim
ridgepole
JavaScript

くらいですかね。
このなかでもstripeには本当に苦労しました。
情報はあるんですがどれもこれもコードの説明?で実践的な情報が本当に少ないです。
なので組み立てるのにかなり時間をかけました。
絶対にstripeに関する記事を出すと約束します。

終わりに

読んでくれてありがとうございました。ぜひcode-sell使ってみてください!
https://www.code-sell.net/

※まだ公開したばかりなので不具合を見つけたらお問い合わせフォームやらQiitaのコメントなどで教えてください。お願いします。

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

Javascirptのメソッドチェーンの説明(初心者向け)

現在記事を修正中

この記事の対象者

配列とメソッドはなんとなくわかる方

メソッドチェーンとは

こんなやつです。

test.html
<body>
    <script>
        arrayA = ["リンゴ","ゴリラ","ラッコ"]
        arrayB = arrayA.slice(1).length
        console.log(arrayB) //2
    </script>
</body>

2行目の右辺のことですね。ドットを挟んでつながってます

arrayB = arrayA.slice(1).length

解説

このarrayA.slice(1).lengthが何を一体しているのかというと

1、配列arrayAに対して .slice(1) で "リンゴ" を配列arrayAから削除した配列を新たに作成。
  ["リンゴ","ゴリラ","ラッコ"]  ⇒  ["ゴリラ","ラッコ"]
2、その削除した配列に対して .length で配列の長さを取得。
  ["ゴリラ","ラッコ"] ⇒ 配列の要素の数は2個

という仕組みになっています。

左側から順番に処理をしていくだけですね。
この順番を必ず意識するようにしてください。

見たことがないメソッドが出てきても基本的にこの考えで解決できると思います。
これがわかれば最初は良いと思います。

ちなみに

左から順番にやっていくというのが分かっていれば

arrayB = arrayA.slice(1).slice(1)

こういうへんてこな書き方もできるというのが理解できると思います。

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

React開発のためのVSCode拡張機能セット

以前から愛用しているものに加え、りあクト!を参考にカスタマイズしました。

参考になれば。

image.png
image.png
image.png

参考

りあクト!

The Complete React Developer Course (w/ Hooks and Redux)


React.js & Next.js超入門

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

【JavaScript】オブジェクトが存在しているのにその中身を参照しようとするとundefinedになる

{ apple: 'りんご', lemon: 'レモン' }

testObjectという名前の上記のようなオブジェクトを参照したいとします。

「りんご」という文字を取り出したいので、

console.log(testObject.apple);
console.log(testObject['apple']);

などとしてもコンソールには

undefined

の表示。

オブジェクト自体はあるのになぜ中身は参照できないの!?!?と困惑するかと思います。
それは、実はオブジェクトではなくてjson型のデータではないでしょうか。

試しに、元のデータを見るため

console.log(testObject);

としてみてください。

{ apple: 'りんご', lemon: 'レモン' }

ではなく

{ "apple": "りんご", "lemon": "レモン" }

のように出てくるかと思います。(※キーも値もダブルクォーテション)

こうなった場合、これはオブジェクトではなくjson型のファイルということです。

結論

testObject = JSON.parse(testObject);

をしましょう。

これをすることでjson型Object型に変換されます。

その後

console.log(testObject.apple);

をすると

りんご

表示できました!

逆に、Object型からjson型に変換したい場合には

testObject = JSON.stringify(testObject);

を使ってくださいね!

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

自分用メモ babelとwebpackとは 

はじめに

プログラミングを勉強し初めて3ヶ月ほど経ちました。私自身javascript、ライブラリのreactを中心に勉強してきました。
書き方自体はなんとなく理解はできてきたのですが、環境構築のツールとして利用されるbabelやwebpackについて全く理解できておりませんでしたのでここでまとめておこうと思い記事にしました。
ここでは、設定ファイルのカスタマイズなどは書いておりませんので、私と同じ初心者の方向けの記事になっていると思います。
間違っている点などあれば教えていただけると幸いです。

Babel

javascriptなどの言語の新しい公文などをどのブラウザでも対応させるようにコンパイルさせるもの。
サポートしていないブラウザでも動くようにコンパイルしてくれるので、ブラウザを意識せずに書ける。

ES6やES7の公文や機能をES5相当の機能を使ってブラウザで実行できるように変換している(ES5が現在ブラウザで広く使われているバージョンだから)

AltJS

コードをコンパイルするという点では、coffeescriptやtypescriptといった、javascriptのコードを生成するAltJSの仲間と言える

AltJSとは「alternative JavaScript」の略で、代替JavaScript言語のことです。 ... AltJSを使用するメリットは、JavaScriptで記述するよりも少ないコード量にできるため、コードの読みやすさや保守性が高まることです。

※違いは、AltJSはjavascriptではないものをjavascriptへコンパイル、babelはjavascriptのコードをどのブラウザでも対応できるバージョンのjavascriptへ変換するもの

インストール

npm install -g babel
babel input.js --out-file output.js

--out-fileは出力するファイル名の指定をするオプション。これをしないと実際にコンパイルはされない!

webpack

役割は指定されたファイルを起点として、そこからimport文を頼りに1つにまとめてjavascriptファイルを出力する。
この1つにまとめる処理をバンドル(bundle)という。そしてそのツールをバンドラーという。
基本の機能、役割は1つでjavascriptファイルをまとめるということ

なぜまとめるのか

http/1.1接続ではブラウザとウェブサーバーの同時接続数が限られるため、複数のファイルの転送に時間がかかる。そのためバンドラーを使い、複数のjsファイルを1つにまとめることが一般的な解決策となっている。

インストール

npm init
npm install webpack webpack-cli

npm initでpackage.jsonファイルが作られます。
そしてwebpackとwebpack-cli(コマンド操作ようのパッケージ)をインストール

JSファイルバンドル以外の機能

ESModules

本来、jsファイルは他のjsファイルを読み込むことができず、htmlファイルで全てscriptタグを利用して書いていました。しかしESModulesを使うとjsファイル同士で読み込みができるため、jsファイルが単独で管理でき、変数の競合やグローバル汚染を防ぐことができる。これによりhtmlファイルとの結合も疎結合になります。また外部ファイルのimportも可能

JSだけでなく、cssや画像もバンドル可能

package.json

npx webpackコマンドでビルドするのもシンプルだが、実際の開発ではnpm scriptsと使う方法が便利と言える。

npm scriptsとはコマンドのショートカットを貼るための機能!

webpack.config.js

このファイルはwebpackの挙動を調整できる。
ファイルのエントリーポイントを指定するentryと出力フォルダーをカスタマイズするoutputがある。
指定がなければデファルトでsrc/index.jsがエントリーポイント、dist/main.jsが出力先になる。

参考記事、参照

AltJSについて
webpackとBabelの基本を理解する(1) ―webpack編―
babelとは

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

Web Speech APIを使って、早口言葉ゲームをつくった

滑舌を改善するトレーニングの仕組み化を目指す

「リモートワークが増えて、気づいたら最近全然人と話してなかった!」ってことはないでしょうか?

私の場合、コロナによって、働き方も生活様式も大きく変わり、対面で人と話すことが劇的に減りました。もちろん、その分、オンラインで人と話すことは圧倒的に増えています。

でも、トータルすると、人と話す頻度って減ってないでしょうか?

それで、ふと思ったのが、

「話す機会が減ると、表情筋が固まる」
「表情筋が固まると、滑舌が悪くなる」
「滑舌が悪くなる、仕事のパフォーマンスが下がる」

ということです。

もちろん「滑舌が悪くなったって全く問題ない」という人はいいのですが、私の場合は、講師業をしているので、滑舌が悪くなると、仕事のパフォーマンスが確実に落ちます。

なので、定期的に滑舌トレーニングをする仕組みが欲しいなと思い、今年中につくることにしました。

以前、滑舌トレーニングのスクールに通っていたので、その時のトレーニングメニューをAI使って、自宅でもできるようにしたいと思っています。また、習慣化を楽しむという意味でも、ゲーミフィケーションを取り入れるつもりです。

今回も少し意識しました。

その一歩目としてのプロダクト

今回作ったのがこちら。

早口言葉ゲーム

こんな感じで使います。

あ、よく見たら、2秒ジャストじゃなく、1.99秒になってる。。
止める時間は調整が必要ですね。

これが結構難しいです。

つくりかた

Web Speech API

これを使うと、簡単に音声認識機能をWEBに追加することができます。

window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
var recognition = new webkitSpeechRecognition();
recognition.lang = 'ja';

recognition.onresult = function (event) {
            //フォームに音声から値を入力
     let results = event.results;
     for (var i = event.resultIndex; i < results.length; i++){
     let mes = results[i][0].transcript;
     document.getElementById('resultText').innerHTML = mes;
     console.log(mes);
     }
}

上記に加えて、音声認識の正誤によって、反応が異なるようにするために、以下のif文を加えました。

if (mes === "生麦生米生卵") {
   let img = document.getElementById("image_place");
   img.src = "image03.png";
   console.log("Yes");
} else {
   let img = document.getElementById("image_place");
   img.src = "image04.png";
   console.log("いいえ");
                }

これで、正誤によって、違う画像が表示されるようになりました。

ストップウォッチ機能の作り方

こちらの記事を参考にさせていただき、実装しました。

JavaScript:正確なストップウォッチを作る

上記の参考サイトからコードを拝借した後、2秒ジャストでストップウォッチを止め、止まると赤で表示されるようにしました。

function startStop()の中に、

setTimeout("startStop();colorChange()", 2006);

を追加した後、以下の、文字の色を変える関数を作りました。

function colorChange(){
    document.getElementById("time").style.color = "red";
}

今後の滑舌トレーニングAIの開発について

今回のようなミニゲームをいくつか作っていきますが、face-api.jsなどの表情認識機能も使って、音声だけでなく、表情から表情筋が動いているかどうかの判定もできるようにしていこうと思います。

表情認識と音声認識を使って、自宅や職場で簡単に滑舌トレーニングができ、かつ、いまの生活の中にトレーニングを組み込んでいける仕組みを作っていこうと思います。

もし気に入っていただければ、LGTMお願いします!!

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

TypeScriptでHello, World!~インストール方法と使い方~

ごあいさつ

ひさしぶりの投稿です!
勉強は続けていたのですが、知識が増えてくると逆に自分の知識不足に気が付き、間違いを恐れて投稿できなくなっていました笑
今回の記事では、自分を含めた初心者向けにTypeScriptのインストール方法と使い方をまとめます。
相も変わらず初心者なので、間違いや補足情報等あればどんどん(やさしく)教えてください!

TypeScriptとは

Microsoftが開発した、JavaScriptの欠点を補うプログラミング言語です。

「JavaScriptの欠点」とは何か。
公式( https://www.typescriptlang.org/docs/handbook/intro.html )によると、

みんなプログラムの型エラーってよくやっちゃうよね。
でもJavaScriptってどんなに複雑なプログラムでも、
実際に動かしてみないと型チェックができないんだよね。不便だねー。
だからTypeScriptは、静的な型チェックができるようにしたよ!
動かす前にプログラムの型があってるかどうか確認できるよ!

だそうです(超意訳)。
つまりTypeScriptは、JavaScriptの
実行しないとエラー確認ができない!
という欠点を、
Javaのようにコンパイル→実行の手順を踏むことで克服しています!えらい!

試しに、誤ったJavaScriptのコードを書いて保存しました。
この時点ではエラーがでません。
image.png
しかしブラウザで開いてみると、
image.png
何も現れないので、コンソール確認でエラー判明。
image.png
たしかにこの手順、特に複雑なプログラムのときはとてもめんどくさいですね。

一方、TypeScriptで誤ったコードを書き、実行前にコンパイルすると、
image.png
おー、教えてくれてありがとう!
image.png
わざわざブラウザで動かさなくていいので、複雑なプログラムでもすぐエラーに気が付けますね!

インストール

さっそくはじめましょう!
初心者でも30分ほどで"Hello, World!"できますよ!

①Node.jsのインストール

htmlに組み込むJavaScriptは、ブラウザ(クライアント)側の実行環境で動作しています。
一方、Node.jsは、サーバ側で動くJavaScriptの実行環境です。
Node.jsの公式サイトからインストーラをダウンロードしてインストールしましょう。
私は「推奨版」を選びました。

②TypeScriptコンパイラのインストール

コマンドラインでTypeScriptのコンパイラをインストールします。
私はVisual Studio Codeのターミナルで行ったので、VSCodeを利用した手順を紹介します。

 1.ローカルの任意の場所にフォルダ作成
 2.VSCodeで、作成したフォルダを開く
 3.左上Viewタブ→Terminalを開く
 4.初期化のコマンド
  ※いろいろ聞かれますが、とりあえず全部EnterでとばしてOK

TERMINAL
> npm init

 5.TypeScriptコンパイラをインストール!

TERMINAL
> npm install -g typescript

 6.バージョン確認

TERMINAL
> tsc -v

 ここでエラーが発生しました。

TERMINAL
    + CategoryInfo          : セキュリティ エラー: ( 
: ) []、P    SSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess     

調査したところ、PowerShellの実行ポリシーがrestrictedになっていることが原因だそうです。
現在のポリシーを次のコマンドで確認すると、restrictedになっていました。

TERMINAL
> Get-ExecutionPolicy
Restricted

次のコマンドを実行してポリシーをBypassに変更したら、無事バージョンの確認ができました。
TypeScriptコンパイラのインストール成功です!

TERMINAL
> Set-ExecutionPolicy Bypass -Scope CurrentUser
TERMINAL
> tsc -v
Version 4.0.3

参考:PowerShellでスクリプトを実行するとセキュリティエラーになるときの対策 | 山本 隆 ( https://www.gesource.jp/weblog/?p=8203 )

実行

インストールお疲れ様でした!
さあ、TypeScriptを実行しましょう!

①コンソール表示

先ほど開いたフォルダ内にhello.tsというファイルを作成し、
コンソール表示のコード書いて保存!

hello.ts
console.log('Hello, World!');

次に、ターミナルでコンパイル
以下のコマンドを実行しましょう。

TERMINAL
> tsc hello.ts

すると、あら不思議!
同じフォルダにhello.jsというファイルが作成されています!
こちらは特にいじる必要なし。

hello.js
console.log('Hello, World!');

最後に実行
ターミナルで以下のコマンドを実行してください。

TERMINAL
> node hello.js
Hello, World!

Hello, World!が表示されました!

②ブラウザ表示

まず、同じディレクトリにindex.htmlというファイルを作成します。
headの中にscriptタグを記述し、コンパイルで作成されるhello.jsを指定します。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf8">
<script src="hello.js"></script>
</head>
<body></body>
</html>

hello.tsの中身は画面表示のコードに変更しましょう。

hello.ts
document.write('Hello, World!');

そしてコンパイル

TERMINAL
> tsc hello.ts

index.htmlを開いてみると…

image.png

Hello, World!が表示されました!

ちなみにDocumentオブジェクトの場合、ターミナルでの実行には失敗するようです。

TERMINAL
> node hello.js
C:\BlankFolder\hello.js:1
document.write('Hello, World!');
^

ReferenceError: document is not defined
    at Object.<anonymous> (C:\BlankFolder\hello.js:1:1)
    at Module._compile (internal/modules/cjs/loader.js:1015:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
    at Module.load (internal/modules/cjs/loader.js:879:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

おわりに

やり方がわかっても、文章で人に説明するのは難しいです。
Qiitaで記事を書こうとすると特に、有識者の方に怒られないよう一生懸命調べるのでいい勉強になります笑
最後まで読んでくださってありがとうございました!

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

スマブラSP大会用ライブ配信レイアウト "ssbutw" を使うまで【NodeCG】

こんにちは。普段はゲームのオフライン大会運営をしながら、日曜大工的に浅瀬でプログラムの勉強をしている者です。

今回NodeCGに関する学びが僅かながら蓄積してきたことと、大変便利そうなライブ配信レイアウトの存在に知ったことをきっかけに筆を取りました。

記事の目的

  • スマブラを始めとする対戦ゲーム勢に「ssbutw」を紹介し、アプリを起動し使うところまでの方法を共有する
  • 備忘録の作成

(アプリの中身を書く話はしません。あくまで使うまで)

想定読者(自己紹介)

  • StreamControlを使ったことがある、またはOBSのテキストソースでスコア管理をしたことがあり、BANステージなどよりリッチな配信レイアウトを使ってみたい
  • スマブラSPをはじめとする対戦ゲームのライブ配信に興味がある
  • 自分で配信レイアウトを作成するほどの技術はないが、調べながらありものを動かすことはできそう

ssbutwとは

ssbutwは、スマブラSP大会用ライブ配信レイアウトの表示・操作・管理を行うアプリです。

ウメブラ・ヒロスマ等のStreamControlをNodeCGで動くように改造したもので、BANステージ表示やSmash.gg連携など機能が追加されています。

オリジナルのページにはスコアボードや操作UIのスクリーンショットがたくさん載っています。
StreamControl等を見慣れている人なら直感的に理解できると思います。(英語です)

ssbutw
https://github.com/crs38c28/ssbutw

作者様
https://github.com/crs38c28

※StreamControlって何?という方は「日本 StreamControl 学会」をご参照ください。

日本 StreamControl 学会
http://streamcontroljapan.blog.jp

できること

従来のStreamControlでもできたこと:

  • 選手情報の表示(名前、Twitter、国旗、スポンサー)
  • スコア表示
  • 大会名、ラウンド表示
  • ファイターアイコン表示
  • Lower thrids表示

ssbutwで追加されていること:

  • BANステージ表示
  • 複数オーバーレイ対応(ウメブラ2種、GENESIS6、FB2019ダブルス、ヒロスマ)
  • 参加者情報インポート(Smash.gg API、Challonge API ※Smash.ggの方は不具合あり?)
  • 参加者情報リスト管理(名前1、名前2、チーム、Twitter、国、使用ファイター)
  • 3言語対応(繁体中国語、英語、日本語)

従来のStreamControlと比較したメリット・デメリット

概して、

「必要な機能を揃えて誰でも使えるようにシンプルにまとめたStreamControl」
vs
「導入までに学習コストがあるが多機能なNodeCGレイアウト」

というイメージです。

メリット

  • BANステージを表示できる
  • 選手情報を分かりやすく管理できる
  • オーバーレイ更新をリモートで役割分担できる

デメリット

  • アプリを起動するまでの環境構築や準備が必要
  • サーバーを用いる場合は接続トラブルが発生する可能性がある

前提知識

基本的にありものを用いるのでプログラムをいじることはありません。
ターミナル, git, node.js, NodeCG, Webサーバに関する浅瀬の知識があると作業の全体像が掴みやすい程度です。

ここでは本記事を読む上で最低限必要なNodeCGに関する情報を簡単に説明します。
ちゃんと知りたい人はHoishinさんの記事やコミュニティDiscordを参照して下さい。というか推奨します。

ライブ配信レイアウトを作るNode.jsのフレームワーク
https://qiita.com/Hoishin/items/36dcea6818b0aa9bf1cd
Twitter
https://twitter.com/nodecg
記事群
https://qiita.com/search?q=nodecg

NodeCGとは、Webの技術を使って動的でリッチな配信レイアウトを作成・管理する技術の様式です。
国内だとRTA in JapanをはじめとするRTA勢の方々が中心になって使用・開発されています。

主な構成要素はDashboardとGraphicsの2つで、2つをまとめたものをBundleと呼びます。
Dashboardは操作部分で、Graphics配信レイアウト部分です。
前者をブラウザで開き、後者は配信ソフトでブラウザソースとして開きます。
前者を操作すると後者に反映されるという流れになります。

色々な方々がBundlesを開発しています。
RTA用、格ゲー用など様々なBundlesが作られています。
今回のssbutwは主にスマブラSP用に作られたもので、

中身としては、Dashboard(操作部分)は

  • スコア入力
  • 選手情報管理
  • 選手情報インポート
  • BANステージ選択

が、Graphics(配信レイアウト)は

  • スコア・プレイヤーネーム表示(ウメブラ・ヒロスマ・GENESISなど各大会仕様のレイアウト)
  • BANステージ表示

が入っています。

普通のWebページと同じようにWebサーバを立ててアプリを起動すれば、配信PC以外の端末(リモート端末や選手用のタブレットなど)から操作が可能です。

使用パターン

主な使い方としては3パターンくらいがあるかと思います。

  1. 配信PC(ローカル)で完結
  2. LAN内で完結
  3. Webサーバを利用

パターン1は配信PC上でNodeCGアプリを起動し、同PC上でスコアボード更新など全てを行う場合です。
パターン2は配信PCと同一LAN内のPC(配信PCでも可)でNodeCGアプリを起動し、そのLAN内の端末からスコアボードを操作したり、選手がBANステージを入力したりする場合です。
パターン3はWebサーバ上でNodeCGアプリを起動し、配信PCやスタッフ/選手用の操作端末から操作する場合です。

BANステージを配信画面に表示させるとしたら、パターン2か3を採用するのが良さそうです。

著者の環境

今回はMacを用います。

macOS Catalina 10.15.4
nodebrew 1.0.1
node.js 12.18.3
npm 6.14.6
NodeCG 6.1.0
zsh

Windowsでもgit bashを用いて動作確認しています。

起動までの流れ

続いて起動までの流れを説明します。
主な流れは以下の通りです。

  1. 必要なものをインストール(git, node.js, nodecg-cli, NodeCG, ssbutw-bundles)
  2. 使用パターンに応じた設定(LAN内の配信 or AWS EC2 上で起動)
  3. アプリを起動

ローカルで完結させる場合と、Webサーバを用いる場合に分けて説明します。

起動までの流れ(ローカル版)

オリジナルのページのInstallation最下部「Directly Download Build Bundle (If you want to add your own dashboard/layout)」の流れに沿っています。

ssbutw Installation
https://github.com/crs38c28/ssbutw/wiki/Installation

0. ターミナルを起動

所謂「黒い画面」のターミナルを起動します。
ここから文字を入力して、必要なものをインストールしたりファイルを操作したりします。

操作する上で cd ls open mkdir などコマンドが必要になります。
必要あれば「ターミナル コマンド」などで調べて下さい。

1. nodebrew, node.jsをインストール

nodebrew: node.jsをバージョンを管理するもの、node.jsを効率よくインストールするのに必要
node.js: javascriptの仲間、NodeCGを使うために必要

1.1. nodebrewのインストール

nodebrewをインストールするためのパッケージ管理ツールであるhomebrewをインストールします。
ターミナルに下記を入力します。

$ sudo /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

nodebrewをインストールします。

$ brew install nodebrew

1.2. node.js をインストール

node.js (v12.18.3) をインストールします。

$ nodebrew install 12.18.3

バージョンを確認してインストールできていることを確認します。

$ node --version
v12.18.3
$ npm --version
v6.14.6

npmは、node.jsを使う上で便利な機能のまとまりを飛び道具的に扱いやすくしてくれる管理システムのようなものです。

参考

初めてのコマンドライン=>npmの利用まで
https://qiita.com/y_sekitoba/items/f0d50afe3884bd22f6d5

2. nodecg-cliをインストール

NodeCGをターミナルから操作するために必要な「nodecg-cli」をインストールします。

$ npm install -g nodecg-cli bower

3. NodeCGをインストールするフォルダを作成

"your-nodecg-project-name" の部分はフォルダ名です。
分かれば何でも良いです。
ターミナルを特に操作していないとフォルダはhomeフォルダに作成されます。
作成する場所を変更したい場合は、あらかじめ cd を用いて移動してください。

$ mkdir your-nodecg-project-name
$ cd your-nodecg-project-name

4. NodeCGをセットアップ

作成したフォルダにNodeCGをセットアップします。

$ nodecg setup

このコマンドを実行して、対象のフォルダに様々なファイルやフォルダが作成されればセットアップは成功です。
※your-nodecg-project-nameが空のフォルダでないとエラーが出ます。

5. bundleをセットする

"your-nodecg-project-name" フォルダ直下の "bundles" フォルダに移動します。

$ cd bundles

ssbutwのbundleをダウンロードします。

$ git clone https://github.com/YujiAIda/ssbutw-bundle

フォルダ名をssbutwに変更します。

$ mv ssbutw-bundle subsets

8. ssbutwをnpmで管理できるようにする

$ cd ssbutw 
$ npm install

9. your-nodecg-project-nameに階層を合わせてアプリを起動

$ cd ../..
$ nodecg start

問題なく起動すれば "http://localhost:9090" で起動している旨が表示されます。
ブラウザのアドレスバーに "http://localhost:9090" を入力して起動を確認できます。

11. 同一LAN内の別端末で開く

同一LAN内の別端末で開く場合は、(ホストのIPアドレス):9090をブラウザから開きます。
ホストのローカルIPアドレスは下記コマンドで調べます。

$ ifconfig

ずらっと文字が表示されますが、"en0(Wi-Fiの場合)" の "inet" の横の数字がローカルIPアドレスです。
Wi-Fi接続でない場合は、それっぽい項目かを試すか、 "ifconfig" でググってください。

12. アプリを終了

Ctrl + Cを入力

起動までの流れ(AWS EC2版)

注意:AWS EC2は利用料金が発生する場合があります。基本的に無料枠の範囲で利用すれば気にする必要はありませんが、ご自身で調べてから使用することを推奨します。

基本的な流れはローカル版と同じです。
AWS EC2のインスタンス(仮想PCみたいなもの)を作成し、そこの上でアプリを起動し、そこにアクセスするという流れです。

1. AWS EC2インスタンス準備

AWSの設定はこちらの記事を参考にしました。

AWS EC2でNodeを動作させる
https://qiita.com/oishihiroaki/items/bc663eb1282d87c46e97

まずはこちらの5章まで進め、以下を完了させます。

  1. AWSアカウント作成
  2. EC2インスタンス作成
  3. SSHでEC2 インスタンスへ接続
  4. node.jsのインストール

2. アクセス関係の設定

次に、外部端末からアクセスする宛先に関する設定と確認を行います。

2.1. パブリックIPアドレスの確認

EC2ダッシュボードから確認します。

2.2. ポート(9090)解放

下記記事を参考にしました。

セキュリティーグループにルールを追加する (サーバーのポートを開放する) - Amazon AWSの使い方 Tips
https://www.ipentec.com/document/amazon-ec2-add-rule-to-security-group

  1. EC2ダッシュボードを開く
  2. 左メニューから「セキュリティグループ」をクリック
  3. 実行中のインスタンスで使用するセキュリティグループ名をクリック
  4. インバウンドルールをクリック
  5. インバウンドルールを編集をクリック。
  6. ルールを追加をクリック。タイプを「カスタムTCP」、ポートを「9090」、ソースを「任意の場所」とする
  7. ルールを保存をクリック。

3.NodeCGの準備

無事AWS EC2インスタンスに接続できたら、上記「起動までの流れ(ローカル版)」の手順でnodecg start まで行います。

4.他のデバイスから開く

EC2ダッシュボードで確認したグローバルIPをブラウザ(ブラウザソース)に入力します。
例: http://[グローバルIP]:9090/

これで開かなければポート9090が開放されているか確認します。
問題なくと動いていれば、複数デバイスで同じページを開き、片方で操作したことがもう一方に反映されることを確認できます。

5.終了時

5.1. アプリの終了

Ctrl + C

5.2. EC2 インスタンスの終了

EC2ダッシュボードから「インスタンスの状態」→インスタンスの終了をクリックします。
インスタンスが終了(≒削除)されるます。
課金されなくなります。

「停止」だけだと、アプリを切っていても課金され続けるので注意。(Elastic IPを占有し続けるかららしい)

備考

  • 元のgithubのbundlesブランチだけgit cloneする方法がわからなかったので、自分用にリポジトリ作りました。

  • 上記のやり方だとnodecg startするとCtrl + Cするまでターミナル が占有されてしまうので、バックグラウンドでアプリを動かし続けるforeverみたいな道具を使うと安全かもしれません。

    Node.jsアプリをLinux環境で常駐化させる forever編
    https://qiita.com/chihiro/items/24ca8ac81cb20c22b47e

  • 今回は勉強がてらAWS EC2を利用しました。
    VirtualBoxや他のレンタル/クラウドサーバーとかでもっといい方法があるかもしれません……。

  • オリジナルのNodeCGアプリはジョーカーが参戦したあたりで更新が止まっています。
    小戦場を追加する際は自身で画像を用意し、うまく名前を変更して画像フォルダに追加する必要があります。
    ファイターの追加はよくわかっていません……。

  • JavaScriptの学習はこちらを利用しました。旧NodeCG Discordでお薦めされていました。

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

ヤマトB2クラウドをFileMakerで動かしたい

送り状発行システムB2クラウドはご存知でしょうか。

上記記載通り、Web上でヤマト運輸の送り状を発行する画期的なシステムです...
※昔はアプリケーションでした。(佐川e飛伝Ⅱのような)

B2クラウドには、ヤマトビジネスメンバーズの登録が必要です。

今回は、ヤマト運輸の送り状を何とか楽にしたいなと思い、備忘録として、記しておきます。

Windowsユーザーのみしかできません。
AdobeAcrobatReaderDCはインストールしといた方がいいかも。
(大体は入ってるのかな...知らんけど...)

ヤマトビジネスメンバーズのログインから行いたいと思います。

ヤマトビジネスメンバーズのログインには、Id・Cd・Pwの3点は必要です。

変数を設定で、3点を変数に格納。
webビュアーにヤマトビジネスメンバーズのリンクと名前を付け忘れずに。
スクリプトwebビュアーの設定で、どんどんJavascriptを実行していこう。

"
javascript:
    function f()
      {
        document.getElementsByName('LOGIN_USER_ID')[0].value='" & $id & "';
        document.getElementsByName('CSTMR_CD')[0].value='" & $cd & "';
     document.getElementsByName('CSTMR_PSWD')[0].value='" & $pw & "';
       };
    f();
    func_request_Link('LOGIN');
"

一応これで私はログインできました。

次に、ヤマトビジネスメンバーズのログイン後、ご利用中のサービスの中に、
送り状発行システムB2クラウドがあります。

ここからは、個々それぞれ違うかもしれませんが。
(自分以外見たことないから正直分からん。)

"
javascript:ybmCommonJs.useService('06');
"

たったこれだけ...
一応本題のB2クラウド画面まできた。
括弧内の06が、自分と違うかもしれません。

それ以降のやり方も一応出来てることは出来てるんだが...
自分も少々詰まってるのでここまで。


ここからは、知ってたら誰か教えて欲しい。

"
javascript:function f(){document.getElementById('file_button').click();};f();
"

これで、CSVファイルを取り込み為のダイアログ?ファイルの選択画面には来るんだけど、
これって直接、ファイル選んでくれないのかな。
FileMakerだけを触って早6年。その他の事を一切知らないからJavascriptの書き方が分からん。
すっごい残念な奴になってるかもしれんが。

これでファイルを決め打ち出来たら便利よな...
誰か助けて。

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

hit and blowというゲームをjavascriptで作ってみた

hit and blowとは

hit and blowとはa-zの文字を使用して
出題者が用意した答えを当てるゲームです。

回答者がa-zの文字を入力し、
答えと同じ順番にあればhit
答えと違う順番だけど、答えに含まれていればblow
というゲームです。

コード

html

    <div class="c-inputBlock">
      <input class="u-mR6 js-input" type="text">
      <button class="u-mR6 js-submit">判定</button>
      <button class="js-submit-clear">クリア</button>
    </div>

    <p><span class="js-result">入力した文字: </span></p>
    <p><span class="js-result-hit">HIT: </span></p>
    <p><span class="js-result-blow">BLOW: </span></p>

javascript

const input = document.querySelector('.js-input');
const submit = document.querySelector('.js-submit');
const submitClear = document.querySelector('.js-submit-clear');
const result = document.querySelector('.js-result');
const resultHit = document.querySelector('.js-result-hit');
const resultBlow = document.querySelector('.js-result-blow');
let flag = false; // 一回判定済みかどうかのフラグ

const answer = "aabb"; // 回答をセット
const answerStrings = answer.split(''); // 回答の文字列を1文字ずつ分割

function clearResult() { // hit数、blow数,入力した文字をクリア
  const resultText = document.querySelectorAll('.js-result-text');
  if (resultText) {
    for (let i = 0; i < resultText.length; i++) {
      resultText[i].innerHTML = "";
    }
  }
}

function clearInput() { // inputの値をクリア
  input.value = "";
}

submitClear.addEventListener('click', () => {
  clearInput();
  clearResult();
});
submit.addEventListener('click', () => {
  const strings = input.value.split(''); // 文字列を1文字ずつ分割
  let hitCount = 0;
  let blowCount = 0;

  if (flag) {
    clearResult();
  }

  for (let i = 0; i < strings.length; i++) {
    if (strings[i] === answerStrings[i]) {
      hitCount++;
    }
    if (answerStrings.includes(strings[i])) {
      blowCount++;
    }
  }


  const setResultText = `<span class="js-result-text">${input.value}</span>`;
  const setResultHitText = `<span class="js-result-text">${hitCount}</span>`;
  const setResultBlowText = `<span class="js-result-text">${blowCount}</span>`;

    result.insertAdjacentHTML("afterend",  setResultText);
    resultHit.insertAdjacentHTML("afterend", setResultHitText);
  resultBlow.insertAdjacentHTML("afterend", setResultBlowText);

  clearInput();
  flag = true;
});

こんな感じで実装しました。
for文の部分は最初、

strings.filter((item, i) => { 
  if (item === answerStrings[i]) {
    hitCount++;
  }
});

とかで実装しようと思ってたましたが配列から新しい配列を生成するメソッドなので
カウントするためだけに使っていいのか悩んでforで実装しました。

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

【個人開発への道①】初心者が、Nuxt.jsでFullCalendarを使ってカレンダーページ作りにチャレンジ!結果は・・・!?

こんにちは!たわちゃんです:sunny:

私は3ヶ月前からプログラミングを学び始めた初心者ではございますが、
プライベートでサービス開発にチャレンジしようとしております・・・!

その開発までの道のりを、これからQiitaにちょこちょこ書いていこうかなと思うので、
さりげな~く応援よろしくお願いします!:relaxed:

構想中のサービス

クラウドファンディング小.png
現在、考えているのがこちらのサービス!

私の兄はマジシャンをしているのですが、常日頃から告知や宣伝活動に困っているのを見てきました。

そこで、兄のような芸人さん、さらには個人経営の店主さんを対象に
告知専用サービスを作ろうと考えました!

主な機能は3つ
(1)スケジュールの管理・共有URLの発行
(2)SNSで簡単にシェア!
(3)告知用の画像もラクラク作成できる!

※「できる・できない」は度外視して考えた機能です!もちろん全部実現させる予定ですが・・・!

そこで、個人開発への道、第一歩として!

(1)の機能で使えるカレンダーページを作ってみることにしました!

前提

カレンダーページを作る前に、Nuxt.jsでサイトを作りました。
Image from Gyazo

トップページに「カレンダーを見る」というボタンを作ったので、
それを押すとカレンダーページに飛ぶようにしたいと思います!

いざ!カレンダーページ作り!

Nuxt.jsでカレンダーコンポーネント『FullCalendar』のVue.js版を使う
高機能でかつ軽快に動作するカレンダーFullCalendarをNuxt.jsで使う

これらの記事を参考に、シンプルだけど機能性が高そうなFullCalendarを使ってページ作成にチャレンジしました!

FullCalendarをインストール

まず、以下のコマンドでFullCalendarのモジュールをインストール!

$ npm install --save @fullcalendar/vue @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/interaction

FullCalendar用のプラグインファイルを作成

pluginsというディレクトリに適当な名前(今回はfullcalendar.js)でファイル作成し、以下の内容を入力!

plugins/fullcalendar.js
import Vue from 'vue'
import Calendar from '~/components/Calendar'

Vue.component('full-calendar', Calendar)

nuxt.config.jsに設定を追記

nuxt.config.js
// 省略
  plugins: [
     // 以下を追記
    { src: '~/plugins/fullcalendar', ssr: false }
  ],
// 省略

Componentを作成

componentsディレクトリにCalendar.vueという名前でファイルを作成し、以下を入力します。

components/calendar.vue
<template>
  <FullCalendar default-view="dayGridMonth" :plugins="calendarPlugins" />
</template>

<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'

export default {
  components: {
    FullCalendar
  },
  data () {
    return {
      // 使用したいプラグインを以下で指定。事前にimportでインポートする。
      calendarPlugins: [ 
        dayGridPlugin,
        timeGridPlugin,
        interactionPlugin
      ]
    }
  }
}
</script>
<style>
@import '~/node_modules/@fullcalendar/core/main.css';
@import '~/node_modules/@fullcalendar/daygrid/main.css';
@import '~/node_modules/@fullcalendar/timegrid/main.css';
</style>

カレンダーを表示させる

私は既に作っていたuserPageというページで表示させたかったので、以下のように追記しました!
fullcalendarを表示させるdivを追加し、呼び出せるようにしました!

userPage.vue
<!--CSS省略-->
<template>
  <div align="center" class="page">

    <h1>My Calendar</h1>
    <div class="columns is-mobile">
      <full-calendar />
    </div>
    <router-link to="/login">
        <button class="btn-calendar"><a class="btn-text">TOPに戻る</a></button>
    </router-link>

  </div>
</template>

<script>
//省略
export default {
  name: 'Schedule',
//省略
    },
</script>

いざ、や~んでぶ!

さぁ、準備は整いました。ページを見てみましょう!
や~ん でぶっ!!!

$ yarn dev

Image from Gyazo

なぜだ・・・。

そのあと、色々模索するも、うまくいかず・・・。
一旦元に戻そうとすると、そもそものページも出ず、以下のようなエラーが。

Image from Gyazo

調べると、キャッシュが残っているとかなんとか。

不幸中の幸いなのかわかりませんが、カレンダーを入れる前の画面に戻す方法だけは会得しました・・・。

(1)node_modules と package-lock-json を削除
(2)以下のコマンドを実行

yarn install 
yarn dev

(参考記事▶nuxtプロジェクトの実行中にエラーが発生しました

こちらでエラーは消えると思うので、私のようにつまずいた方の参考になりますよう・・・。

とりあえずのGoogleカレンダー

FullCalendarはもうちょい調査が必要なので・・・
とりあえず何かカレンダー表示させられないかと調べました。

Googleカレンダーの埋め込みなら私でもできそうだったのでチャレンジ!

Googleカレンダーの設定 ▶ マイカレンダーの設定 ▶ 表示させたいカレンダーを選択 ▶ カレンダーの統合

この手順で埋め込みコードを取得することができます!

今回はとりあえず、こちらをuserpageに追加!

  <div align="center" class="page">

    <h1>My Calendar</h1>
    <iframe src="https://calendar.google.com/calendar/embed?src=twtjudy%40gmail.com&ctz=Asia%2FTokyo" 
    style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
  <br>
    <router-link to="/login">
        <button class="btn-calendar"><a class="btn-text">TOPに戻る</a></button>
    </router-link>

  </div>

これは簡単に表示されました。とりあえず良かった・・・。

結果まとめ&今後の課題

・Nuxt.js難しい…。FullCalendarを表示できるように、引き続きチャレンジ!
・CSSもひどいので、ライブラリとか使ってシンプル&見やすさを意識する
・PCとスマホどっちで見ても綺麗にするにはどうすればいいのか調べる
・エラーから学ぶことも多いので、エラー出てもくじけない

今回はうまく行きませんでしたが、これからチャレンジすることのハードルを認識できたので良かったです。

ちょっと楽観的になってる部分があったので、ちゃんと気を引き締めて、課題を把握し、
ひとつひとつ潰していかないとサービス完成しないなと・・・

不安と焦りは強くなりましたが、ストレッチきいた目標がある方が成長できると思うので頑張ります。

おまけ

ボタンを押すとページ遷移するっていうのを覚えたら楽しくなったので、
遊びのボタンを2つ作りました。

Image from Gyazo

「撃たれる」を押すと、以前自分で作ったステイサムに撃たれるアプリに飛びます。
image.png
参照▶ジェイソン・ステイサムに「死にたくないなら手を挙げろ!」と言われるのが夢だったので、自分でそんなアプリを作りました。

次に「映画を見る」を押すと、以前自分で作ったステイサムのオススメ映画を教えてくれるアプリに飛びます。

参照▶あなたにピッタリなジェイソン・ステイサムの映画を教えてくれるアプリを作りました【Vue.js】

たのしい・・・。

自分は遊びもどこかに入れないと、モチベが保てないということも今回でわかったので
全部ひっくるめてどういうサービスを作っていくか方向性を決めていくのも大事だとわかりました。

個人開発への道は長い・・・。

(つづく)

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

vuejs-datepickerで動的に多言語対応する方法

概要

ユーザーが設定している表示言語設定に応じてvuejs-datepickerの表示言語を動的に変更するという実装をする際、vuejs-datepickerの表示言語を親コンポーネントから制御する方法に詰まったのでメモを残しておくの巻

困ったこと

親コンポーネントとvuejs-datepickerを使用している子コンポーネントが存在し、親コンポーネントから渡すpropsに応じて子コンポーネント側で使用しているvuejs-datepickerの表示言語を変更すること

解決策

全ての言語を配列としてimportし、dataオブジェクトの任意のプロパティの値として指定しておきます(下記コードの場合、all_langという名前でimportし、dataオブジェクトのlanguagesというプロパティの値としてall_langを指定しています)。
そして親コンポーネント側から使用したい言語を文字列でpropsとして渡し、その文字列をもとにlanguagesの配列から使用したい言語オブジェクトを抽出し、それをdatepickerのlanguageプロパティに指定すれば解決しました!あとは何らかの方法でjaやenなど言語の識別文字列をどこからか取得するだけ。
ちなみに下記の場合、親コンポーネントからスペイン語を指定しており、デフォルト日本語になっています!

App.vue
<template>
    <calender
        v-model="form.specical_date"
        title="ブロックタイトル"
        placeholder="プレースホルダー"
        language="es"
    />
</template>

<script>
import Calender from './components/Calender.vue';
export default {
    components: {
        Calender,
    },
    data() {
        return {
            form: {
                specical_date: null,
            },
        };
    },
};
</script>
Calender.vue
<template>
    <div>
        <span>{{ title }}</span>
        <datepicker
            format="yyyy-MM-dd"
            :language="languages[language]"
            :placeholder="placeholder"
            :clear-button="true"
            @input="updateDate"
        />
    </div>
</template>

<script>
import Datepicker from 'vuejs-datepicker';
import * as all_lang from 'vuejs-datepicker/dist/locale';
export default {
    components: {
        Datepicker
    },
    props: {
        title: {
            type: String,
            default: '',
        },
        placeholder: {
            type: String,
            default: ''
        },
        language: {
            type: String,
            default: 'ja'
        }
    },
    data() {
        return {
            languages: all_lang,
        };
    },
    methods: {
        updateDate(val) {
            this.$emit('input', val);
        },
    }
};
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JS・TS】コーディングTips集

概要

JavaScript/TypeScriptを書く中で、自分自身の気づき、他の方から頂いたアドバイスをメモとして残してきました。
その中で、使用頻度が高そうで、知っていれば誰でも簡単に実践できる物を抜粋して記事にしました。
ですので、主にJavaScript/TypeScriptの使用歴が浅い(プログラミングの歴が浅い)方向けに少しでも参考になれば幸いと考えています。

(※JS/TSに限った事では無いものも含まれます。また、こちらに記載した記法が必ずしも優れていると言うわけではありません。本記事はあくまでも、JS・TSを利用した際にこんな記法もあるよという紹介が主要点です。)

早期returnを利用する

条件を満たす場合に直ぐに return することで、コードのネストを減らし、コードの見通しを良くするテクニックです。
簡単な例としまして下記のコードが、

const checkNumber = (num: number) => {
    if (num === 2) {
       return "2です。"
    } else {
       return "2以外です。"
   }
}

この様に書き換えられます。

const checkNumber = (num: number) => {
    if (num === 2) return "2です。"
    return "2以外です。"
}

分割代入を利用する

const user = {
    name: "Name1",
    age: 23,
    userName: "User1"
}

console.log(user.name, user.age, user.userName)

が、下記の様に書き換えられます。

const user = {
  name: 'Name1',
  age: 23,
  userName: 'User1',
}
// Object Destructuring
const { name, age, userName } = user

console.log(name, age, userName)

上記以外でも分割代入を使用する事で色々な事ができます。
下記に色々なパターンがリストされています。

アロー関数をより簡潔に

const hoge = () => {
  return 'HOGE'
}

{}returnを省略して下記の様に書き換えられます。

const hoge = () => "HOGE"

filterメソッドで配列から空のstringを取り除く

const hogeArray = ['hoge1', 'hoge2', ''].filter(string => string)

console.log(hogeArray) //=> ["hoge1", "hoge2"]

コメントで頂きましたが、下記のような書き方も可能です。

const hogeArray = ['hoge1', 'hoge2', ''].filter(Boolean)

短絡評価(Short Circuit Conditionals)を駆使する

下記のコードはisAvailabletrueならばaddToCartメソッドを実行しています。

if (isAvailable) {
  addToCart()
}

上記はこの様に書き換える事ができます。

isAvailable && addToCart()

変数をオブジェクトのキーとして利用する

下記の様に [ ] で変数を囲ってあげましょう。

const key = "name"

// なぜかqiitaで表示されなかったのでコメントにしました。
var obj = {
  // [key]: "Name",
}

console.log(obj) //=> { "name": "Name" }

条件付きで変数を設定する

下記のコードではtimezoneに初期値を与え、userがpreferredTimezoneを持つ場合にはその値を上書きしています。

let timezone = 'EastAsia/Tokyo'

if (user.preferredTimezone) {
  timezone = user.preferredTimezone
}

上記はこの様に書き換える事ができます。

const timezone = user.preferredTimezone || 'EastAsia/Tokyo'

nullとundefinedの両方を確認する

value === null ではなく、value == null を使用してあげましょう。

const nullCheck = (v: any) => {
    return v === null
}

const nullAndUndfinedCheck = (v: any) => {
   return v == null
}

// nullCheck
nullCheck(undefined) //=> false
nullCheck(null) //=> true

// nullAndUndfinedCheck
nullAndUndfinedCheck(undefined) //=> true
nullAndUndfinedCheck(null) //=> true

参考: Is there a way to check for both null and undefined?

特定のプロパティのみオブジェクトから抜き出す

必要なプロパティのみを抜き出す事ができます。

const object = { a: 5, b: 6, c: 7 }
const picked = (({ a, c }) => ({ a, c }))(object)

console.log(picked) // { a: 5, c: 7 }

もしくは分割代入を使用する事で、下記の様に抜き出せます。

const obj = {
  name: 'Fenton',
  age: 21,
}

let { age, ...subset } = obj

console.log(subset) //=> { "name": "Fenton" }

if文の簡略化にオブジェクトを使用する

const howIsBoo = (state) => {
  if (state === 'HUNGRY') return 'WANTS FOOD';
  if (state === 'SAD') return 'CRYING';
  if (state === 'HAPPY') return 'LAUGHING'
  return 'SLEEPING'
}

はオブジェクトを使用する事で、下記の様に書き換えが可能です。

const booFeelsTable = {
  HUNGRY: 'WANTS FOOD',
  SAD: 'CRYING',
  HAPPY: 'LAUGHING',
}
const howIsBoo = state => booFeelsTable[state] || 'SLEEPING'

変数を正規表現で使用する

下記のように、new RegExp でRegExpのオブジェクトを作成することで使用可能です。

var replace = 'regex'
var re = new RegExp(replace, 'g')
'mystring'.replace(re, 'newstring')

How do you use a variable in a regular expression?

参考

JS-TS Tips | K-Sato's Blog

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

整数に3桁区切りカンマを入れる (JavaScript)

結果

処理前

123456789

処理後

123,456,789

方法1

toLocaleStringを使う
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString

方法2

NumberFormatを使う
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat

方法3

humanize を使う
https://github.com/HubSpot/humanize

実装

実装方法3

準備

yarn add humanize-plus

実装

import Humanize from 'humanize-plus'

let r = Humanize.intComma(123456789)
console.log(r) // 123,456,789
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Symbol from NEMのSDKを利用して暗号と署名検証を行う方法

今回はsymbol-sdkを利用してブロックチェーンを使わずに暗号化と署名検証を使う方法を説明します。

事前準備

スクリプト埋め込み

(script = document.createElement('script')).src = 'https://xembook.github.io/nem2-browserify/symbol-sdk-pack-0.21.0.js';
document.getElementsByTagName('head')[0].appendChild(script);

chromeのコンソールを開いてsymbol-sdkのスクリプトを埋め込んでください。

ライブラリインポートとアカウント生成

nem = require("/node_modules/symbol-sdk");

alice = nem.Account.generateNewAccount(nem.NetworkType.TEST_NET);
bob = nem.Account.generateNewAccount(nem.NetworkType.TEST_NET);

今回の暗号化や署名に使用するライブラリのインポートとアカウントを生成しておきます。

暗号化

message = 'Symbol from NEM!';
encodedMessage = nem.Crypto.encode(alice.privateKey,bob.publicKey,message);

送信者の秘密鍵、受信者の公開鍵、メッセージの順に指定します。
受信者の公開鍵でメッセージを暗号化する、という点がポイントです。

"2561a6aa1c5ea51b3971fc907d28678db6d28c568a30249541eb9d411eced23ee0f432a58459acb741f7b963"

暗号化できました。

復号化

decodedHex = nem.Crypto.decode(
  bob.privateKey, 
  alice.publicKey,
  "2561a6aa1c5ea51b3971fc907d28678db6d28c568a30249541eb9d411eced23ee0f432a58459acb741f7b963"
)

nem.Convert.decodeHex(decodedHex)

受信者の秘密鍵、送信者の公開鍵、暗号化メッセージの順に指定します。
受信者の秘密鍵で復号化するという点がポイントです。
出力されたHEX文字をデコードします。

"Symbol from NEM!"

無事復号化されました。

署名

payload = nem.Convert.hexToUint8(nem.Convert.utf8ToHex("Symbol from NEM"));
signature = nem.Convert.utf8ToHex(nem.KeyPair.sign(alice.keyPair, payload));

署名したいメッセージをHEX変換してUint8Arrayに変換します。
署名したいアカウントのキーペアを指定して署名、HEX変換します。
メッセージを作成したアカウントの秘密鍵で署名するというのがポイントです。

"7FCF7614D60BF4506DEC7D1B55AA1A0972881FA8FC40D0D0FBAAAF77E036E7988270E57631D49FCE253C4FB992E17C9360FA948B6626B2954E7DAB84DA7D6E01"

署名テキストが出力されました。

検証

nem.KeyPair.verify(
  alice.keyPair.publicKey,
  nem.Convert.hexToUint8(nem.Convert.utf8ToHex("Symbol from NEM")),
  nem.Convert.hexToUint8( 
 "7FCF7614D60BF4506DEC7D1B55AA1A0972881FA8FC40D0D0FBAAAF77E036E7988270E57631D49FCE253C4FB992E17C9360FA948B6626B2954E7DAB84DA7D6E01")
)

検証したいアカウントの公開鍵、検証したいメッセージ、署名テキストの順で指定します。
メッセージを作成したアカウントの公開鍵で検証する、というのがポイントです。

true

無事、trueが出力されました。

このように、暗号、復号、署名、検証はブロックチェーンと切り離して使うことができます。場合によってはこれらの出力結果をメールでやりとりして信頼性検証を行うこともできます。

では、ブロックチェーンを使うことの意味とは何でしょうか?
このことを、ぜひ一度振り返って考えてみるきっかけにしていただければ幸いです。

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