LoginSignup
3
2

More than 1 year has passed since last update.

LWCで電子署名ごっこ(お絵描き)しよう

Posted at

背景と本記事の方針

  • そんなような業務要件があったので「きついっすねーどこのパッケージ買いましょうね」と受け流してたんですが、個人の趣味の範囲でちょっと書いてみたら動きはしたので、せっかくなので記事にします
  • LWC,JavaScript,HTML一般に関する知識/技術は持ち合わせていないのでほぼスルーか参考リンク載せるだけ。素人がググりながらどうにか動くとこまでこぎ着けた過程を記します
  • 間違ったこと書いてる、読みづらい等あればコメントください

忙しい人のための解答

SalesforceLabsがGithub上に「これぞ」という完成品を公開してくれてます感謝感謝感謝
https://github.com/SalesforceLabs/DrawAnnotations

実装の前提

目標

電子署名もどきにお絵描きができるLightningコンポーネントをつくりたい

ライブラリについて

  • 素の状態でも十分書けるようだけど、今回は外部ライブラリを使って実現

  • ライブラリ選定
    パッと調べた結果、以下2つがヒット。今回は諸々考慮しfabric.jsを採用

jSignature fabric.js
機能概要 手書き署名専用 汎用的な画像・図形操作
要件充足
ライセンス MIT MIT
最新リリース 2012.11.1 2022.2.21

下準備

ライブラリのソースを貰ってくる

弄る

  • このfabric.js、一部処理にてLWC実装時のセキュリティ要件(Lightning Lockerかな?)を満たしていないらしい
  • SalesforceLabsが公開するソース上で修正済みのfabric.jsソースが見られるので、そちらを参考に修正
    (SalesforceLabsの修正済ソースと、同verの元ソースとで差分確認のこと)

具体的には下記の修正をしてるっぽい

  • Avoid using anything created
    DOMImplementation.createHTMLDocument()しないよう修正
  • scroll might not work
    Element.scrollTop, scrollLeftを参照しないよう修正
  • Cannot Create Elements
    Document.createElement()しないよう修正

静的リソースに格納する

Trailhead: 静的リソースの使用

HTMLの実装

説明

  • コンテナを置いてやるだけ
    • JavaScript上でinnerHTMLにCanvasを置いてやる
    • HTML上に直置きしたCanvas要素を使うと怒られる
      • Lightning Locker周りの制約と思われるけど詳細は不明
test.html
<template>
  <div class="test-container"></div>
</template>

JavaScriptの実装

説明

  • (1) サードパーティライブラリ使用時のいつものやつで、メソッドをインポート、呼び出してやる
    Platform Resource Loader

  • (2) 予めレイヤー分けしたCanvasをテキストベースで用意して、コンテナのinnerHTMLにセットしてやる

  • (3) コンテナの幅を取得して、それに基づいて適当にCanvasサイズを設定

    • 「コンテナの幅 = コンポーネント自体の幅」はプラットフォーム側で上手いことやってくれるので便利
  • (4) 予め用意したCanvasのlowerレイヤーの方をベースにCanvasインスタンス生成

    • upperレイヤーの方とwrapperもそれぞれプロパティに渡してやる
    • "isDrawingMode" プロパティで手書きモードのon/offを制御
test.js
import { LightningElement } from 'lwc';
// (1) いつもの
import { loadScript } from 'lightning/platformResourceLoader';
import fabricjs from '@salesforce/resourceUrl/fabricjs';

// (2) 階層化されたCanvas要素をjs側で用意
const CONTAINER_HTML = `<div class="test-wrapper">
	<canvas class="test-cvs-lower"></canvas>
	<canvas class="test-cvs-upper"></canvas>
	</div>`;

export default class Test extends LightningElement {
	// fabric.Canvasインスタンス用変数
	fab;

	// (1) 同じくいつもの
	connectedCallback(){
		Promise.all([
			loadScript(this, fabricjs)
		])
		.then(() => {
			// (2) 用意したCanvas要素をHTML上のコンテナにセット
			const container = this.template.querySelector('.test-container');
			container.innerHTML = CONTAINER_HTML;
			const wrapperEl = this.template.querySelector('.test-wrapper');
			const lowerEl   = this.template.querySelector('.test-cvs-lower');
			const upperEl   = this.template.querySelector('.test-cvs-upper');

			// (3) コンテナの幅に基づいてCanvasサイズを設定
			let cvsWidth  = container.getBoundingClientRect().width;
			let cvsHeight = container.getBoundingClientRect().width * 0.4;

			// (4) fabric.Canvasインスタンスの生成
			this.fab = new fabric.Canvas(lowerEl, {
				wrapperEl: wrapperEl,
				upperCanvasEl: upperEl,
				width: cvsWidth,
				height: cvsHeight,
				backgroundColor: 'rgb(230,230,230)',
				isDrawingMode: true,
			});
		});
	}
}

要点

  • SalesforceLabs様を参考にライブラリのソースを弄ってやること
  • HTML側にはコンテナだけ置いて、JavaScript側でinnerHTMLにCanvasをセットしてやること
  • セットするCanvasはラッパー・下位レイヤー・上位レイヤーの構造にしてやること

デモ

bandicamのロゴが麗しい
Videotogif.gif

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