vue3-esign
Version:
A canvas signature component of vue
283 lines (282 loc) • 10.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
import { defineComponent, ref, reactive, computed, watch, onBeforeMount, onBeforeUnmount, onMounted, openBlock, createElementBlock } from "vue";
const __default__ = { name: "Vue3Esign" };
const _sfc_main = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({}, __default__), {
props: {
width: { default: 800 },
height: { default: 300 },
lineWidth: { default: 4 },
lineColor: { default: "#000000" },
bgColor: { default: "" },
isCrop: { type: Boolean, default: false },
isClearBgColor: { type: Boolean, default: true }
},
emits: ["update:bgColor"],
setup(__props, { expose, emit }) {
const props = __props;
const hasDrew = ref(false);
const resultImg = ref("");
let points = reactive([]);
const canvasTxt = ref(null);
const startX = ref(0);
const startY = ref(0);
const isDrawing = ref(false);
const sratio = ref(1);
const canvas = ref(null);
const ratio = computed(() => props.height / props.width);
const stageInfo = computed(() => {
var _a;
return (_a = canvas.value) == null ? void 0 : _a.getBoundingClientRect();
});
const myBg = computed(() => props.bgColor ? props.bgColor : "rgba(255,255,255,0.5)");
watch(myBg, (newValue) => {
canvas.value.style.background = newValue;
});
const $_resizeHandler = () => {
var _a, _b;
const myCanvas = canvas.value;
myCanvas.style.width = `${props.width}px`;
const realw = parseFloat(window.getComputedStyle(myCanvas).width);
myCanvas.style.height = `${ratio.value * realw}px`;
canvasTxt.value = myCanvas.getContext("2d");
(_a = canvasTxt.value) == null ? void 0 : _a.scale(1 * sratio.value, 1 * sratio.value);
sratio.value = realw / props.width;
(_b = canvasTxt.value) == null ? void 0 : _b.scale(1 / sratio.value, 1 / sratio.value);
};
onBeforeMount(() => {
window.addEventListener("resize", () => {
$_resizeHandler();
});
});
onBeforeUnmount(() => {
window.removeEventListener("resize", $_resizeHandler);
});
onMounted(() => {
canvas.value.height = props.height;
canvas.value.width = props.width;
canvas.value.style.background = myBg.value;
$_resizeHandler();
document.onmouseup = () => {
isDrawing.value = false;
};
});
const mouseDown = (e) => {
e.preventDefault();
isDrawing.value = true;
hasDrew.value = true;
const obj = {
x: e.offsetX,
y: e.offsetY
};
drawStart(obj);
};
const mouseMove = (e) => {
e.preventDefault();
if (isDrawing.value) {
const obj = {
x: e.offsetX,
y: e.offsetY
};
drawMove(obj);
}
};
const mouseUp = (e) => {
e.preventDefault();
if (isDrawing.value) {
const obj = {
x: e.offsetX,
y: e.offsetY
};
drawEnd(obj);
isDrawing.value = false;
}
};
const touchStart = (e) => {
e.preventDefault();
hasDrew.value = true;
if (e.touches.length === 1) {
const obj = {
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
};
drawStart(obj);
}
};
const touchMove = (e) => {
e.preventDefault();
if (e.touches.length === 1) {
const obj = {
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
};
drawMove(obj);
}
};
const touchEnd = (e) => {
e.preventDefault();
if (e.touches.length === 1) {
const obj = {
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
};
drawEnd(obj);
}
};
const drawStart = (obj) => {
var _a, _b, _c, _d, _e;
startX.value = obj.x;
startY.value = obj.y;
(_a = canvasTxt.value) == null ? void 0 : _a.beginPath();
(_b = canvasTxt.value) == null ? void 0 : _b.moveTo(startX.value, startY.value);
(_c = canvasTxt.value) == null ? void 0 : _c.lineTo(obj.x, obj.y);
canvasTxt.value.lineCap = "round";
canvasTxt.value.lineJoin = "round";
canvasTxt.value.lineWidth = props.lineWidth * sratio.value;
(_d = canvasTxt.value) == null ? void 0 : _d.stroke();
(_e = canvasTxt.value) == null ? void 0 : _e.closePath();
points.push(obj);
};
const drawMove = (obj) => {
canvasTxt.value.beginPath();
canvasTxt.value.moveTo(startX.value, startY.value);
canvasTxt.value.lineTo(obj.x, obj.y);
canvasTxt.value.strokeStyle = props.lineColor;
canvasTxt.value.lineWidth = props.lineWidth * sratio.value;
canvasTxt.value.lineCap = "round";
canvasTxt.value.lineJoin = "round";
canvasTxt.value.stroke();
canvasTxt.value.closePath();
startY.value = obj.y;
startX.value = obj.x;
points.push(obj);
};
const drawEnd = (obj) => {
var _a, _b, _c, _d, _e;
(_a = canvasTxt.value) == null ? void 0 : _a.beginPath();
(_b = canvasTxt.value) == null ? void 0 : _b.moveTo(startX.value, startY.value);
(_c = canvasTxt.value) == null ? void 0 : _c.lineTo(obj.x, obj.y);
canvasTxt.value.lineCap = "round";
canvasTxt.value.lineJoin = "round";
(_d = canvasTxt.value) == null ? void 0 : _d.stroke();
(_e = canvasTxt.value) == null ? void 0 : _e.closePath();
points.push(obj);
points.push({ x: -1, y: -1 });
};
const generate = () => {
const pm = new Promise((resolve, reject) => {
var _a, _b, _c;
if (!hasDrew.value) {
reject(new Error("Warning: Not Signned!"));
return;
}
const resImgData = canvasTxt.value.getImageData(0, 0, canvas.value.width, canvas.value.height);
canvasTxt.value.globalCompositeOperation = "destination-over";
canvasTxt.value.fillStyle = myBg.value;
(_a = canvasTxt.value) == null ? void 0 : _a.fillRect(0, 0, canvas.value.width, canvas.value.height);
let my_resultImg = canvas.value.toDataURL();
canvasTxt.value.clearRect(0, 0, canvas.value.width, canvas.value.height);
(_b = canvasTxt.value) == null ? void 0 : _b.putImageData(resImgData, 0, 0);
canvasTxt.value.globalCompositeOperation = "source-over";
if (props.isCrop) {
const crop_area = getCropArea(resImgData.data);
let crop_canvas = document.createElement("canvas");
const crop_ctx = crop_canvas.getContext("2d");
crop_canvas.width = crop_area[2] - crop_area[0];
crop_canvas.height = crop_area[3] - crop_area[1];
const crop_imgData = (_c = canvasTxt.value) == null ? void 0 : _c.getImageData(...crop_area);
crop_ctx.globalCompositeOperation = "destination-over";
crop_ctx == null ? void 0 : crop_ctx.putImageData(crop_imgData, 0, 0);
crop_ctx.fillStyle = myBg.value;
crop_ctx == null ? void 0 : crop_ctx.fillRect(0, 0, crop_canvas.width, crop_canvas.height);
my_resultImg = crop_canvas.toDataURL();
crop_canvas = null;
}
resolve(my_resultImg);
});
return pm;
};
const reset = () => {
var _a;
(_a = canvasTxt.value) == null ? void 0 : _a.clearRect(0, 0, canvas.value.width, canvas.value.height);
if (props.isClearBgColor) {
emit("update:bgColor", "");
canvas.value.style.background = "rgba(255,255,255,0)";
}
points = [];
hasDrew.value = false;
resultImg.value = "";
};
const getCropArea = (imgData) => {
let topX = canvas.value.width;
let btmX = 0;
let topY = canvas.value.height;
let btnY = 0;
for (let i = 0; i < canvas.value.width; i++) {
for (let j = 0; j < canvas.value.height; j++) {
const pos = (i + canvas.value.width * j) * 4;
if (imgData[pos] > 0 || imgData[pos + 1] > 0 || imgData[pos + 2] || imgData[pos + 3] > 0) {
btnY = Math.max(j, btnY);
btmX = Math.max(i, btmX);
topY = Math.min(j, topY);
topX = Math.min(i, topX);
}
}
}
topX++;
btmX++;
topY++;
btnY++;
const data = [topX, topY, btmX, btnY];
return data;
};
expose({ generate, reset, stageInfo });
return (_ctx, _cache) => {
return openBlock(), createElementBlock("canvas", {
ref_key: "canvas",
ref: canvas,
style: { "max-width": "100%", "display": "block" },
onMousedown: mouseDown,
onMousemove: mouseMove,
onMouseup: mouseUp,
onTouchstart: touchStart,
onTouchmove: touchMove,
onTouchend: touchEnd
}, null, 544);
};
}
}));
_sfc_main.install = function(Vue) {
Vue.component(_sfc_main.name, _sfc_main);
};
const components = { Vue3Esign: _sfc_main };
const install = function(Vue) {
Object.values(components).forEach((component) => {
console.log("component", component);
console.log("component.name", component.name);
Vue.component(component.name, component);
});
};
if (typeof window !== "undefined" && window.Vue)
install(window.Vue);
var index = {
install
};
export { _sfc_main as Vue3Esign, index as default };