2025年7月11日金曜日

QRcodeを生成する(APIは使わない)

 FileMakerでQRcodeを生成してみます。


テーブルは1個

フィールドはこれだけ。


「えっ!QRcodeを生成するテーブルとデータテーブルを分けないの?」
はい、分けません。
だって、生成側の源泉になるのがグローバルフィールドですし、リレーションやポータルのオーバーヘッドが無いし、スクリプトやレイアウトが1つのテーブル内で完結してるから印刷とか、後々一括生成とかも楽に作りたいから。


あと、APIも使いません。
それはPCやGOとかローカル環境も想定しているからです。(今回のは繋いだ状態)DCN方法はサンプルファイルに記載しています。

なによりもメンテが楽です。

今回は住所をQR化しています。

ダウンロード(win11,FMP19.6以降)
(すみません、デザインとか何も考えてません)



ということで、簡単な流れを書きます。


①JavaScriptのQRcode生成ライブラリを読み込む。もしくはDCNで埋め込む。

②①で生成させたQRは一時的にWebビューアーに表示させる。
(FileMakerでダイレクトにQRコードを画像化させることはできません)

DOM(ドム)Document Object Model側に描画された後にPNG化して画像として表示させる。(SVGやCanvas化されたものをBase64形式に変換する)






①JavaScriptのQRcode生成ライブラリを読み込む。もしくはDCNで埋め込む。
についてですが、ローカルで使う場合は読込先のコードをまるっきし埋め込んで使ってもよいと思います。

で、今回のqr-code-stylingという読込先。
FileMakerとの相性はいい方だと思いますよ。

昔からある GitHub: davidshimjs/qrcodejs については
もう少しJavaScriptの知識が無いとFileMakerとの連携が難しいです。

JavaScript側に「FileMakerへの指示(スクリプト呼び出し)」を明示的に組み込まないと、FileMakerとの連携は行われません。Base64変換も FileMakerへのデータ返却もなにもされないので、JavaScript側からFileMaker側に引数を取らせてLOOPさせるとか、けっこう大変です。

工数ばかりかかるし、レイアウトをまたぐと意外と厄介だったりするので、同テーブルにqr-code-stylingなら20分作業!みたいな感じでいいのかと思います。




DATA::g_QRテンプレートHTML

これにhtmlを入れます。htmlの中身は省略します。
サンプルにはJavaScriptのコメント入れてありますのでご参考に。



Webビューアーには

DATA::g_住所QR

これだけ入れておきます。




g_QRテンプレートHTML
(これにhtmlの中身を入れておく)

FileMakerのスクリプトで

DATA::g_住所QRg_QRテンプレートHTMLの中身を渡す。
webビューアーに表示させる。
Base64でPNG画像に変換してWebビューアーの表示を消す。


ここでFileMaker側のスクリプトは2つ必要となります。

QR_webビューアーに表示



qrcode (JavaScript側で動かすのでスクリプト名は変えないように)



QR_webビューアーに表示について
今回は住所をQR化しているので、QRを読み込んだ後、GoogleMAPで開きます。



FileMaker側のスクリプト


変数を設定[$mapURL;値:

Substitute (

    "https://www.google.com/maps?q=" & GetAsURLEncoded ( DATA::住所 ) ;

    "'" ; "%27"

  )]

"%27"は 16進数でのASCIIコード 0x27 = 10進数で 39
ASCIIコード 39番は → シングルクォート '


大事なのはスクリプト内の
変数を設定[ $html ; 値 : Substitute ( $template ; "<<MAP_URL>>" ; $mapURL )]
ですね。


これはg_QRテンプレートHTML内の"<<MAP_URL>>"をFileMaker側の住所データに置き換えているってことです。


<<MAP_URL>>
FileMakerなどでスクリプトから置換されるプレースホルダの事です。



しかし、本来は

DATA::g_QRテンプレートHTML内に

htmlのbody内でいうと

  <div id="qrcode"></div>


  <script>

    const qr = new QRCodeStyling({

      width: 300,

      height: 300,

      data: "", // ← 初期データは空(doItからセット)

      image: "",

      dotsOptions: { color: "#000", type: "square" },

      backgroundOptions: { color: "#fff" },

      qrOptions: { errorCorrectionLevel: "L" }

    });


    function doIt(mapURL) {

      // URLをセットしてQRコード更新

      qr.update({ data: mapURL }); //ここで遅くなる


      // QRコード描画(1回のみ)

      const target = document.getElementById("qrcode");

      target.innerHTML = ""; // ← 再生成時の二重描画防止

      qr.append(target);


      // 少し待って画像として取得 → FileMakerに渡す

      setTimeout(() => {

        qr.getRawData("png").then(blob => {

          const reader = new FileReader();

          reader.onloadend = () => {

            const base64data = reader.result.split(",")[1];

            if (window.FileMaker) {

              FileMaker.PerformScript("qrcode", base64data);

            }

          };

          reader.readAsDataURL(blob);

        });

      }, 300);

    }

  </script>


にするのですが、
ちょっと処理が遅く感じます。

qr.update({ data: xxx })は、一度オブジェクトが生成された後に、値を書き換えて、再描画して〇〇という処理になるので、任意のタイミングをとってQR変換させるにはいいけど、一回っきりの<<MAP_URL>>にした方がダイレクトで処理は速いし、一括でLOOP発行させるときも楽。FileMakerっぽくて好きかなと。




なので、html全文

<!DOCTYPE html>

<html>

<head>

  <meta charset="utf-8">

  <title>QR</title>

  <script src="https://cdn.jsdelivr.net/npm/qr-code-styling@1.5.0/lib/qr-code-styling.js"></script>

</head>

<body style="margin:0;display:flex;justify-content:center;align-items:center;height:100vh;">

  <div id="qrcode"></div>

  <script>

    const qr = new QRCodeStyling({

      width:300,

      height:300,

      data: "<<MAP_URL>>",  //ここにダイレクトにデータを読み込ませ

      image: "",

      dotsOptions: { color: "#000", type: "square" },

      backgroundOptions: { color: "#fff" },

      qrOptions: { errorCorrectionLevel: "L" }   // LとかMとかHとか

    });


    qr.append(document.getElementById("qrcode"));


    // Base64エクスポートしてFileMakerに渡す

    setTimeout(() => {

      qr.getRawData("png").then(blob => {

        const reader = new FileReader();

        reader.onloadend = () => {

          const base64data = reader.result.split(",")[1];

          if (window.FileMaker) {

            FileMaker.PerformScript("qrcode", base64data);

          }

        };

        reader.readAsDataURL(blob);

      });

    }, 500); // SVG生成完了後に画像化

  </script>

</body>

</html>




FileMaker側のスクリプトにも最後に
Web ビューアで JavaScript を実行 [ オブジェクト名: "Web" ; 関数名: "doIt" ; 引数: $mapURL ]
を入れています。

関数名: "doIt" を入れておいてもqrオブジェクトの初期化時にすでに済んでいるのでエラーにはならず条件付きで動くんです。
関数名: "doIt" は動いていないけど、取ってしまうと全く動かなくなる。

早い処理にするために"doIt" など明示的な意味合いで使用しています。



サンプルですが、グローバルフィールド内のhtml文が丸ごと消えていたら

下に「万が一html復活」というボタンを用意しましたので復活してください


0 件のコメント:

コメントを投稿

QRcodeを生成する(APIは使わない)

  FileMakerでQRcodeを生成してみます。 テーブルは1個 フィールドはこれだけ。 「えっ!QRcodeを生成するテーブルとデータテーブルを分けないの?」 はい、分けません。 だって、生成側の源泉になるのがグローバルフィールドですし、リレーションやポータルのオーバーヘ...