@furo/ui5
Version:
SAP UI5 Web Components data bindings for furo-web
215 lines (189 loc) • 4.41 kB
JavaScript
import { LitElement, html, css } from 'lit';
import { FBP } from '@furo/fbp';
import SignaturePad from 'signature_pad/dist/signature_pad.js';
/**
* `furo-sign-pad`
* Simple pad to sign or draw something
*
*
* @fires {Base64} sign-updated - Fired when sign gets new painting, with base encoded image.
*
* @summary draw or sign
* @element furo-ui5-sign-pad
* @appliesMixin FBP
*/
export class FuroUi5SignPad extends FBP(LitElement) {
constructor() {
super();
/**
* @private
*/
this._field = {}; // ensure that field is available
}
/**
* flow is ready lifecycle method
* @private
*/
_FBPReady() {
super._FBPReady();
this.canvas = this.shadowRoot.querySelector('canvas');
this.signaturePad = new SignaturePad(this.canvas, {});
const processChange = this._debounce(() => this.encodeImage());
this.signaturePad.addEventListener('afterUpdateStroke', () => {
processChange();
});
setTimeout(() => {
this.resize();
if (this.getAttribute('image')) {
this.setImage(this.getAttribute('image'));
}
}, 1);
this.signaturePad.clear();
}
/**
* Trigger this method after a resize.
*
*/
resize() {
if (this.canvas) {
const ratio = 1;
this.canvas.width = this.canvas.offsetWidth * ratio;
this.canvas.height = this.canvas.offsetHeight * ratio;
this.canvas.getContext('2d').scale(ratio, ratio);
}
}
/**
*
* @private
* @return {CSSResult}
*/
static get styles() {
// language=CSS
return css`
:host {
display: block;
box-sizing: border-box;
height: 184px;
width: 300px;
cursor: pointer;
position: relative;
}
canvas {
width: 100%;
height: 100%;
}
div.dots {
position: absolute;
top: 24px;
bottom: 24px;
left: 24px;
right: 24px;
pointer-events: none;
border: 1px dashed var(--sapField_BorderColor, #89919a);
}
`;
}
/**
* @private
* @returns {TemplateResult}
*/
render() {
// language=HTML
return html`
<canvas></canvas>
<div class="dots"></div>
`;
}
/**
* Disables the pad
*/
disable() {
this.signaturePad.off();
}
/**
* Enables the pad
*/
enable() {
this.signaturePad.on();
}
/**
* @private
*/
_setEmpty(b) {
this.empty = b;
}
/**
* Clears the image. This also updates the bound field.
*/
clear() {
this.signaturePad.clear();
this.encodeImage();
// super.clear();
this._field._value = '';
}
/**
* Adds the encoded image to the canvas.
*
* Maybe you want to clear first.
*
* @param encodedImage {imageURL}
*/
putImage(encodedImage) {
const img = new Image();
img.src = encodedImage;
const ctx = this.canvas.getContext('2d');
img.onload = () => {
ctx.drawImage(img, 0, 0); // Or at whatever offset you like
};
img.src = encodedImage;
}
/**
* Encodes the image using the type and encodingOptions (quality) defined.
* The encoded image is available in the `image` property.
*/
encodeImage() {
this.image = this.canvas.toDataURL(this.type, this.encodingOptions);
this._setEmpty(this.signaturePad.isEmpty());
const customEvent = new Event('sign-updated', {
composed: true,
bubbles: true,
});
customEvent.detail = this.image;
this.dispatchEvent(customEvent);
this._field._value = this.image;
return this._field._value;
}
/**
* bind a entity field
* @param entityField
*/
bindData(entityField) {
this._field = entityField;
// update drawing on changes from outside
this._field.addEventListener('this-field-value-changed', () => {
this.signaturePad.clear();
this.putImage(this._field._value);
});
setTimeout(() => {
if (this._field._value) {
this.putImage(this._field._value);
}
}, 16);
}
/**
* @private
* @param func
* @param timeout
* @return {(function(...[*]): void)|*}
*/
_debounce(func, timeout = 333) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
}
window.customElements.define('furo-ui5-sign-pad', FuroUi5SignPad);