vue3-signature-pad
Version:
A Vue3 Signature Pad
504 lines (433 loc) • 15.8 kB
JavaScript
var vue=require('vue'),OriginalSignaturePad=require('signature_pad'),mergeImages=require('merge-images');function _interopDefaultLegacy(e){return e&&typeof e==='object'&&'default'in e?e:{'default':e}}var OriginalSignaturePad__default=/*#__PURE__*/_interopDefaultLegacy(OriginalSignaturePad);var mergeImages__default=/*#__PURE__*/_interopDefaultLegacy(mergeImages);function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}var ImageTypesEnum;
(function (ImageTypesEnum) {
ImageTypesEnum["PNG"] = "image/png";
ImageTypesEnum["JPEG"] = "image/jpeg";
ImageTypesEnum["SVG"] = "image/svg+xml";
})(ImageTypesEnum || (ImageTypesEnum = {}));
var SaveOutputsEnum;
(function (SaveOutputsEnum) {
SaveOutputsEnum["FILE"] = "file";
SaveOutputsEnum["DATA_URL"] = "data_url";
})(SaveOutputsEnum || (SaveOutputsEnum = {}));
function binaryStringToFile(bstr, filename, mimeType) {
var lastModified = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Date.now();
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {
type: mimeType,
lastModified: lastModified
});
}
function dataURLtoFile(dataUrl, filename) {
var lastModified = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Date.now();
var arr = dataUrl.split(',');
var leftSideArr = arr[0];
var parts = leftSideArr.match(/:(.*?);/);
if (!parts) {
throw new Error('Invalid data url');
}
var mimeType = parts[1];
var bstr = atob(arr[1]);
return binaryStringToFile(bstr, filename, mimeType, lastModified);
} // eslint-disable-next-line
var convert2NonReactive = function convert2NonReactive(observerValue) {
return JSON.parse(JSON.stringify(observerValue));
};
var TRANSPARENT_PNG = {
x: 0,
y: 0,
src: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
};var DEFAULT_OPTIONS = {
dotSize: (0.5 + 2.5) / 2,
minWidth: 0.5,
maxWidth: 2.5,
throttle: 16,
minDistance: 5,
backgroundColor: "rgba(0,0,0,0)",
penColor: "black",
velocityFilterWeight: 0.7 // onBegin: (event) => {},
// onEnd: (event) => {},
};
var script = /*#__PURE__*/vue.defineComponent({
name: "VueSignaturePad",
props: {
modelValue: {
type: [String, File],
required: false
},
width: {
type: Number,
default: 250,
validator: function validator(value) {
return 0 <= value && value <= 99999;
}
},
height: {
type: Number,
default: 150,
validator: function validator(value) {
return 0 <= value && value <= 99999;
}
},
saveType: {
type: String,
default: ImageTypesEnum.PNG,
validator: function validator(value) {
var allowedValues = Object.values(ImageTypesEnum);
if (!allowedValues.includes(value)) {
console.warn("The Image type is incorrect! Supported ones are ".concat(allowedValues.join(", "), "."));
return false;
}
return true;
}
},
saveOutput: {
type: String,
default: SaveOutputsEnum.DATA_URL,
validator: function validator(value) {
var allowedValues = Object.values(SaveOutputsEnum);
if (!allowedValues.includes(value)) {
console.warn("The save output is incorrect! Supported ones are ".concat(allowedValues.join(", "), "."));
return false;
}
return true;
}
},
customStyle: {
type: Object,
default: function _default() {
return {};
}
},
options: {
type: Object,
default: function _default() {
return DEFAULT_OPTIONS;
}
},
images: {
type: Array,
default: function _default() {
return [];
}
}
},
setup: function setup(props, context) {
// state
var state = vue.reactive({
cacheImages: [],
onResizeHandler: null,
signaturePad: {},
signatureData: TRANSPARENT_PNG
}); // ref: signaturePadCanvas
var signaturePadCanvas = vue.ref(null); // computed properties
var signaturePadCanvasElement = vue.computed(function () {
if (!signaturePadCanvas.value) {
throw new Error('No canvas could be found with this "ref" in the template');
}
return signaturePadCanvas.value;
});
var propsImagesAndCustomImages = vue.computed(function () {
var nonReactiveProrpImages = Array.from(convert2NonReactive(props.images));
var nonReactiveCachImages = Array.from(convert2NonReactive(state.cacheImages));
return [].concat(_toConsumableArray(nonReactiveProrpImages), _toConsumableArray(nonReactiveCachImages));
}); // watch
vue.watch(function () {
return props.options;
}, function (nextOptions) {
Object.keys(nextOptions).forEach(function (option) {
if (Object.prototype.hasOwnProperty.call(state.signaturePad, option)) {
state.signaturePad[option] = nextOptions[option];
}
});
}); // methods
function resizeCanvas() {
var canvas = signaturePadCanvasElement.value;
var data = state.signaturePad.toData();
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
var context = canvas.getContext("2d");
if (context) {
context.scale(ratio, ratio);
}
state.signaturePad.clear();
state.signatureData = TRANSPARENT_PNG;
state.signaturePad.fromData(data);
}
function saveSignature() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : props.saveType;
var encoderOptions = arguments.length > 1 ? arguments[1] : undefined;
if (state.signaturePad.isEmpty()) {
if (props.saveOutput === SaveOutputsEnum.FILE) {
return {
isEmpty: true,
file: null,
output: SaveOutputsEnum.FILE
};
} else if (props.saveOutput === SaveOutputsEnum.DATA_URL) {
return {
isEmpty: true,
data: null,
output: SaveOutputsEnum.DATA_URL
};
} else {
throw new Error("This saveOutput ".concat(props.saveOutput, " is not supported"));
}
}
var dataURL = state.signaturePad.toDataURL(type, encoderOptions);
state.signatureData.src = dataURL;
if (props.saveOutput === SaveOutputsEnum.FILE) {
return {
isEmpty: false,
file: dataURLtoFile(dataURL, 'signature'),
output: SaveOutputsEnum.FILE
};
} else if (props.saveOutput === SaveOutputsEnum.DATA_URL) {
return {
isEmpty: false,
data: dataURL,
output: SaveOutputsEnum.DATA_URL
};
} else {
throw new Error("This saveOutput ".concat(props.saveOutput, " is not supported"));
}
}
function undoSignature() {
var record = state.signaturePad.toData();
if (record) {
state.signaturePad.fromData(record.slice(0, -1));
}
}
function completedSignature() {
var savedSignature = saveSignature();
var inputData = null;
if (savedSignature.output === SaveOutputsEnum.FILE) {
inputData = savedSignature.file;
} else if (savedSignature.output === SaveOutputsEnum.DATA_URL) {
inputData = savedSignature.data;
}
context.emit("input", inputData);
}
function mergeImageAndSignature(customSignature) {
state.signatureData = customSignature;
return mergeImages__default['default']([].concat(_toConsumableArray(props.images), _toConsumableArray(state.cacheImages), [state.signatureData]));
}
function addImages() {
var images = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
state.cacheImages = [].concat(_toConsumableArray(state.cacheImages), _toConsumableArray(images));
return mergeImages__default['default']([].concat(_toConsumableArray(props.images), _toConsumableArray(state.cacheImages), [state.signatureData]));
}
function fromDataURL(dataURL) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var callback = arguments.length > 2 ? arguments[2] : undefined;
state.signaturePad.fromDataURL(dataURL, options, callback);
}
function fromData(data) {
state.signaturePad.fromData(data);
}
function toDataURL() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ImageTypesEnum.PNG;
var encoderOptions = arguments.length > 1 ? arguments[1] : undefined;
return state.signaturePad.toDataURL(type, encoderOptions);
}
function toData() {
return state.signaturePad.toData();
}
function lockSignaturePad() {
state.signaturePad.off();
}
function openSignaturePad() {
state.signaturePad.on();
}
function isEmpty() {
return state.signaturePad.isEmpty();
}
function getPropImagesAndCacheImages() {
return propsImagesAndCustomImages.value;
}
function clearCacheImages() {
state.cacheImages = [];
return state.cacheImages;
}
function clearSignature() {
state.signaturePad.clear();
context.emit("input", null);
} // hooks
vue.onMounted(function () {
var canvas = signaturePadCanvasElement.value;
var signaturePad = new OriginalSignaturePad__default['default'](canvas, _objectSpread2({
onEnd: completedSignature
}, props.options));
state.signaturePad = signaturePad;
state.onResizeHandler = resizeCanvas;
window.addEventListener("resize", state.onResizeHandler, false);
resizeCanvas();
});
vue.onBeforeUnmount(function () {
if (state.onResizeHandler) {
window.removeEventListener("resize", state.onResizeHandler, false);
}
});
return _objectSpread2(_objectSpread2({}, vue.toRefs(state)), {}, {
signaturePadCanvas: signaturePadCanvas,
// computed properties
propsImagesAndCustomImages: propsImagesAndCustomImages,
// methods
resizeCanvas: resizeCanvas,
saveSignature: saveSignature,
undoSignature: undoSignature,
mergeImageAndSignature: mergeImageAndSignature,
addImages: addImages,
fromDataURL: fromDataURL,
toDataURL: toDataURL,
fromData: fromData,
toData: toData,
lockSignaturePad: lockSignaturePad,
openSignaturePad: openSignaturePad,
isEmpty: isEmpty,
getPropImagesAndCacheImages: getPropImagesAndCacheImages,
clearCacheImages: clearCacheImages,
clearSignature: clearSignature
});
},
render: function render() {
var width = this.width,
height = this.height,
customStyle = this.customStyle;
var baseStyle = {
width: "".concat(width, "px"),
height: "".concat(height, "px")
};
return vue.h("div", {
style: _objectSpread2(_objectSpread2({}, baseStyle), customStyle)
}, [vue.h("canvas", {
style: {
width: "100%",
height: "100%"
},
ref: "signaturePadCanvas"
})]);
}
});// Import vue component
// Default export is installable instance of component.
// IIFE injects install function into component, allowing component
// to be registered via Vue.use() as well as Vue.component(),
var component = /*#__PURE__*/(function () {
// Assign InstallableComponent type
var installable = script; // Attach install function executed by Vue.use()
installable.install = function (app) {
app.component('SignaturePad', installable);
};
return installable;
})(); // It's possible to expose named exports when writing components that can
// also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
// export const RollupDemoDirective = directive;
var namedExports=/*#__PURE__*/Object.freeze({__proto__:null,'default': component});// only expose one global var, with named exports exposed as properties of
// that global var (eg. plugin.namedExport)
Object.entries(namedExports).forEach(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
exportName = _ref2[0],
exported = _ref2[1];
if (exportName !== 'default') component[exportName] = exported;
});module.exports=component;
;