Google Apps Scriptで座席表を作ろう - イメージマップ編【GAS】

前回のお話、jQueryのライブラリを利用して、タイル状に配置した座席表を作りました。多くの事業所では、このような四角い配置で良いかと思いますが、実際には最近流行りのオシャレ事務所となると、机の配置から椅子の並びなどが結構フリースタイルな状況で、それに対応しようとすると、通常の手法では座席表を実現するのは困難になります。

今回、背景に事務所内座席レイアウトに対して、クリッカブルマップキャンバスを使って、座席表を実現してみたいと思います。

今回使用するスプレッドシートおよびソフトウェア

※2022年8月4日、より簡単なSVG画像を使ったレスポンシブ対応の座席表管理システムを作りました。

Google Apps ScriptでSVGを使ったイメージマップを操作 – 応用編【GAS】

概要

今回は背景の画像とキャンバスそしてクリッカブルマップを被せるjq_imgMapToCanvas2.jsというライブラリを使っています。レイヤ1に通常事務所座席レイアウト、レイヤ2にクリッカブルマップ(更にマウスオーバー時に色が変わる仕様)となるライブラリなのですが、キャンバスが一つですと、この色が変わる機能の為に、マウスオーバー後にそのままだと描写したキャンバスイメージが全部消えるため、座っている人の名前については、もうひとつキャンバスを被せて、そちらに描写する3枚サンド仕立てになっています。

下から背景画像、真ん中に座ってる人の名前(canvas1つ目)、その上にクリッカブルマップ(canvas2つ目)といった状況です。

クリッカブルマップとはHTML初期の頃からある「1つの画像上に座標を持って、複数のリンクを貼る技術」で、例えば1枚の地図にて、エリアごとにリンク先が異なるように座標でエリア分けしてリンクを貼れる技術です。今ではSVG画像などを用いるケースもあります。作るのが少々大変なので、この後の準備の項目では、それを容易にするサービスを利用してタグを生成します。

キャンバスとはHTML5を代表する技術で「HTML上にタグを持って画像を生成し、更にそれを操作する為の技術」で、アニメーションなどをさせる事も可能。画像と言ってもいわゆるPNGやJPGのような画像ファイルではなく、ベクターグラフィックスのようなものをタグで生成する事が出来ます。

キャンバスを重ねる時には、z-indexの値でそれぞれのキャンバスにレイヤ位置を持たせるのですが、マウスで直接的に操作出来るのは一番上のレイヤになります。重ねるとその下のレイヤは直接的には操作が出来ないので注意が必要です。

事前準備

画像を準備する

今回、ベースとなる800x500の枠付き画像を用意しておきました。この画像の上にお好きなペイントエディタなどを利用して、椅子や机などを配置して、フロアマップ画像を作成してください。業務で使ってるものは、1000x500のサイズで作っています。

画像形式はpngでもjpgでも可ですが、jpgの場合画質は落とすと掠れたりするので、100%画質で作ることをおすすめします。

図:こんな具合に作りました

クリッカブルマップを生成する

座席表データはXYの座標を持ったクリッカブルマップのHTMLコードが必要になります。といっても、タグ打ちでこれは人間では出来ません。そこで、これを容易にしてくれるHTML Imagemap Generatorを利用します。

以下の手順でフロアマップにクリッカブルマップを作り込みます。

  1. HTML Imagemap Generatorを開く
  2. フロアマップ画像をドラッグアンドドロップする。
  3. 四角形や丸、多角形の3種で椅子の部分を上手に囲む。丸の場合は、丸を囲むのではなく、丸を四角く囲む感じで作ります。
  4. 右サイドに生成されたHTMLコードがクリッカブルマップです。これを控えて置きます。
  5. Google Apps Script側にmapタグ内のareaタグデータをimagemap.htmlとして作って書き込んでおく

図:丸で椅子にクリッカブルマップを作ってる様子

図:imagemap.htmlを作成しておく

クリッカブルマップにIDを振る

生成されたareaタグをimagemap.htmlに貼り付けたら、各areaタグにIDを振ります。これは座席表シートのシートデータのID列と対応します。クリック時にこのIDを読み取ってスプレッドシート側のIDを見つけにいきます。areaタグ内に「id="park1"」といった具合に、タグを編集しておきましょう。

今回のサンプルは14席なので、スプレッドシート側もpark14まで作ってあります。

図:このIDはシートのレコード特定に重要な役目を果たします。

シートデータのXY座標を整備する

シートデータには、各IDにはラベルを表示する為のXY座標の数値を入れる必要があります。canvasのどの位置に表示するか?を決めるものですが、今回は椅子の丸の真上に表示するよう調整しています。クリッカブルマップのcoordsの値は(X座標, Y座標, 大きさ)を示していますので、これを利用します。

今回のケースでは、coordsのX座標 - 26した値をシートデータの座標Xの値として格納する。coordsのY座標 - 10した値をシートデータの座標Yの値として格納します。全てのIDのXY座標の値をこのような方法で埋めてください。

図:XY座標の値はラベルを表示する位置になります。

画像をアップロードして・・・

フロアマップ画像自体の画像はどこかに保存しておかなければなりません。其のためだけにサーバを用意してってのも勿体無いので、今回はGoogle Driveに画像をアップロードし、その画像を直接利用します。

  1. Google Driveに画像をアップロードする
  2. 画像のアクセス権限はG Suiteユーザならばドメインのユーザに許可をしておけば良いでしょう。今回はリンクを知ってる人全員に公開としています。
  3. 共有リンクを取得しましょう。
  4. Google Drive Direct Link Generatorを開きます。
  5. Enter Your sharing URLに3.で取得したリンクを貼り付けて、create direct linkをクリック
  6. Output Linkをコピーします。これは直接画像を開けるリンクです。これを控えておきましょう。

図:外部共有する場合には注意を払いましょう

図:フロアマップ画像への直リンクURLが取得できます。

ソースコード

今回、jq_imgMapToCanvas2.jsを利用し、クリッカブルマップにマウスオーバーで色の変わるライブラリをGoogle Apps Scriptの中で利用しています(imagemap2canvas.htmlに埋め込んでいます)。

jq_imgMapToCanvas2.jsについて

オリジナルのjq_imgMapToCanvas2.jsは、canvasを動的に生成するコードになっています。しかし、今回は座席ラベルの表示などをする関係上予め、HTML上にcanvasを作ってあるので、以下のようにコードを変更してあります。

  • canvas設置の部分、var canvasdocument.getElementById("canvas")として変更をしています。
  • また、クリッカブルマップのz-indexは5を設定。今回のアプリではもっとも上のレイヤになります。こうしておかないと、クリッカブルマップとホバー効果が無効になってしまいます(この上にさらにレイヤを置いてしまうと、そのレイヤに被さってしまうため)
  • ただしこのjq_imgMapToCanvas2.jsですが、electronでこのまま利用すると、エラーが出て動きません。そこでelectronで使いたい場合には、if (!jQuery.support.opacity) {}のセクションはコメントアウトするか?削除する必要があります。G_vmlCanvasManagerが原因で止まってしまいます。

GAS側コード

  • シートの確保の為の関数と解放の為の関数は前回のライブラリ編と同じですので、今回は割愛しています。
  • nowparkareaではシートデータの座標データまで取得して含めて返しています。
  • clearpark関数は毎日0時にスクリプトトリガーによって、シートデータをクリアする関数です。

HTML側コード

  • 起動時にシートデータを取得して、onImagemap関数でIDがcanvas2のタグに確保済みユーザのラベルを表示しています。
  • 背景画像およびクリッカブルマップ自体はIDがcanvasのタグに描画しています。IDがcanvasはz-indexが5番目のレイヤになるので、ここではもっとも上のレイヤとしています。
  • 座席確保したユーザのラベルはz-indexが4番目となるように、CSSにてIDがcanvas2のレイヤはz-index:4を指定しています。
  • 座席確保のダイアログ、座席解放のダイアログをそれぞれ用意しています。
  • 座席開放時はデータをクリアした後、再度データを読み込ませています。canvasは一度リセットするためにclearrectで指定した座標のエリアをリセットしています。
  • 今回画像が800x500のサイズで作っている為、全体のdiv、背景画像、canvasのそれぞれのサイズも800x500で指定しています。
  • panel2のIDを持つdivはホバーやクリッカブルマップを反映する親divとなります。子がIDがcanvasのdivとなります。
  • canvastextがcanvas2にユーザ名のラベルを反映する為の関数となります。

使い方と実行

使い方

このアプリの使い方ですが、

  1. スプレッドシート上のメニューより「座席表Plus」⇒「セットアップ」を実行する
  2. ユーザ表をきちんと整備しておく。ユーザ表のIDにないIDを入力されてもシートが確保されないようになります。
  3. スプレッドシート上のメニューより「リセットトリガー設置」を実行すると、毎日0時に座席データがクリアされるようになります。

実行結果

  • 丸をクリックするとダイアログが表示され、ユーザ表にあるIDと一致するIDを入力するとシートが確保されます。
  • 座席の解放をクリックすると、確保済みシートが解放され、canvasがリロードされます。
  • 丸はマウスオーバーで色が変わります。
  • トリガーを設置しておくと、毎日0時にシートデータがクリアされリセットされます。

高解像度対応で文字の滲みをなくす

低解像度なPCだとあまり気にならなかった今回のイメージマップ版座席表ですが、最近のPCやRetina Displayなモニターだと文字の滲み(アンチエイリアスなのかどうかわからないけれど)が結構気になるレベル。やはり文字がはっきり見えたほうが良い!!ということで、改造しました。

今回の改造ポイントは

  1. 文字表示を行うcanvasは別レイヤとして追加する(canvas3とする)
  2. 文字ははっきりクッキリきれいなフォントで見えるようにする
  3. 文字のバックにあるボックスは文字サイズに合わせたボックスの幅に自動調整する

これを実現するテクニックは

  • canvas内で指定するheightとwidthは実際に表示するサイズの2倍サイズを指定する(今回下地の画像が800x500のサイズなので、1600x1000で指定をしています。
  • 同時にCSSでそのcanvasのheightとwidthは実際の800x500の指定をするというのがポイントになります。
  • canvasの初期化の時点でcontextのscaleを二倍サイズにするコードを入れておく
  • 背景のボックスは文字幅をmeasureTextで取得してそのサイズを指定してあげるようにする

これらをコードにすると

コード:canvas3のサイズを指定するCSS

コード:canvas3の初期化時にスケール2倍を指定

※OnParkのcanvasも文字データをクリアするコードもcanvas2ではなくcanvas3にしておくのを忘れずに。

コード:canvas3に文字を描画する関数

※canvasに他のcanvas同様のclass="canvas"をつけておくと、文字が横に伸びてしまうので、canvas3では余計なclass指定は外しておきましょう。

コード:HTML側のcanvas3の状態

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)