LoginSignup
3
2

More than 1 year has passed since last update.

Blocklyのカスタムブロックでasync/awaitを使って現在のBitcoinの価格を知りたい!

Posted at

結論から

Image from Gyazo

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/blockly/blockly.min.js"></script>
  <script>
    Blockly.Blocks['console_log'] = {
      init: function () {
        this.appendDummyInput()
          .appendField(new Blockly.FieldTextInput("ログ"), "log")
          .appendField("出力");
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(230);
        this.setTooltip("");
        this.setHelpUrl("");
      }
    };
    Blockly.JavaScript['console_log'] = function (block) {
      const text_log = block.getFieldValue('log');
      const code = 'console.log(\''+ text_log+'\');\n';
      return code;
    };

    Blockly.Blocks['wait'] = {
      init: function () {
        this.appendDummyInput()
          .appendField(new Blockly.FieldNumber(1), "sec")
          .appendField("秒待つ");
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(230);
        this.setTooltip("");
        this.setHelpUrl("");
      }
    };
    Blockly.JavaScript['wait'] = function (block) {
      const number_sec = block.getFieldValue('sec');
      const code = 'await sleep('+ number_sec+');\n';
      return code;
    };
  </script>

  <title>Blockly test</title>
</head>

<body>
  <!-- Toolboxのブロック -->
  <xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
    <block type="math_number">
      <field name="NUM">123</field>
    </block>
    <block type="text"></block>
    <block type="text_print"></block>
    <block type="console_log"></block>
    <block type="wait"></block>
  </xml>

  <!-- Workspace -->
  <div id="blocklyDiv" style="height: 480px; width: 600px;"></div>

  <!-- 実行ボタン -->
  <button onclick="run()">実行</button>

  <script>
    const demoWorkspace = Blockly.inject('blocklyDiv',
      {
        media: 'https://unpkg.com/blockly/media/',
        toolbox: document.getElementById('toolbox')
      });

    function sleep(time) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, time * 1000);
      });
    }

    function run() {
      const code = '(async () => {'+Blockly.JavaScript.workspaceToCode(demoWorkspace) + '})();';
      console.log(code);
      try {
        eval(code);
      } catch (e) {
        alert(e);
      }
    }
  </script>
</body>
</html>

大事な部分は

const code = '(async () => {'+Blockly.JavaScript.workspaceToCode(demoWorkspace) + '})();';

code生成したあとに、asyncで囲んで、即時実行しているところです。

カスタムブロックでは関数実行だけで、その関数は予め用意しておくとよいかなと思います。

せっかくなのでWebAPIを使って現在のビットコインの値段を調べてみよう

Image from Gyazo

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/blockly/blockly.min.js"></script>
  <script>
    Blockly.Blocks['console_log'] = {
      init: function () {
        this.appendDummyInput()
          .appendField(new Blockly.FieldTextInput("ログ"), "log")
          .appendField("出力");
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(230);
        this.setTooltip("");
        this.setHelpUrl("");
      }
    };
    Blockly.JavaScript['console_log'] = function (block) {
      const text_log = block.getFieldValue('log');
      const code = 'console.log(\''+ text_log+'\');\n';
      return code;
    };

    Blockly.Blocks['wait'] = {
      init: function () {
        this.appendDummyInput()
          .appendField(new Blockly.FieldNumber(1), "sec")
          .appendField("秒待つ");
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(230);
        this.setTooltip("");
        this.setHelpUrl("");
      }
    };
    Blockly.JavaScript['wait'] = function (block) {
      const number_sec = block.getFieldValue('sec');
      const code = 'await sleep('+ number_sec+');\n';
      return code;
    };

    Blockly.Blocks['webapi_btc'] = {
      init: function () {
        this.appendDummyInput()
          .appendField("現在のビットコインの価格(USD)");
        this.setOutput(true, null);
        this.setColour(230);
        this.setTooltip("");
        this.setHelpUrl("");
      }
    };
    Blockly.JavaScript['webapi_btc'] = function (block) {
      var code = 'await getBitcoinRate()';
      return [code, Blockly.JavaScript.ORDER_NONE];
    };
  </script>

  <title>Blockly test</title>
</head>

<body>
  <!-- Toolboxのブロック -->
  <xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
    <block type="math_number">
      <field name="NUM">123</field>
    </block>
    <block type="text"></block>
    <block type="text_print"></block>
    <block type="console_log"></block>
    <block type="wait"></block>
    <block type="webapi_btc"></block>
  </xml>

  <!-- Workspace -->
  <div id="blocklyDiv" style="height: 480px; width: 600px;"></div>

  <!-- 実行ボタン -->
  <button onclick="run()">実行</button>

  <!-- axiosライブラリ -->
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

  <script>
    const demoWorkspace = Blockly.inject('blocklyDiv',
      {
        media: 'https://unpkg.com/blockly/media/',
        toolbox: document.getElementById('toolbox')
      });

    function sleep(time) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, time * 1000);
      });
    }

    // USD
    async function getBitcoinRate() {
      // axiosでBTCPriceのAPIを叩きます(少し時間がかかる)
      const res = await axios.get('https://api.coindesk.com/v1/bpi/currentprice.json');
      // 取得できたBTCのUSD価格を抜き出す
      return res.data.bpi.USD.rate_float;
    }

    function run() {
      const code = '(async () => {'+Blockly.JavaScript.workspaceToCode(demoWorkspace) + '})();';
      console.log(code);
      try {
        eval(code);
      } catch (e) {
        alert(e);
      }
    }
  </script>
</body>
</html>

注意点

codeを文字列で返すとき、最後セミコロン(;)があるとアラート出力するときに、 alert(await getBitcoinRate();); となってしまってシンタックスエラーになってしまいます。

ここらへん全部対応できないことあるかもなぁ

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2