first commit
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
"use strict";
|
||||
(function (root, factory) {
|
||||
if (typeof exports === "object" && typeof module !== "undefined") {
|
||||
module.exports = factory()
|
||||
} else if (typeof define === "function" && define.amd) {
|
||||
define(factory)
|
||||
} else {
|
||||
root = root || self
|
||||
root.Signature = factory()
|
||||
}
|
||||
})(typeof self !== "undefined" ? self : this, function () {
|
||||
function isHexColor(color) {
|
||||
return typeof color === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)
|
||||
}
|
||||
|
||||
function Signature(options) {
|
||||
var self = this
|
||||
var history = []
|
||||
var drawing = false
|
||||
var currentPoint = null
|
||||
var activePointerId = null
|
||||
var canvas
|
||||
var context
|
||||
|
||||
self.obj = options && !Array.isArray(options) ? options : {}
|
||||
self.option = {
|
||||
el: self.obj.el ? self.obj.el : "body",
|
||||
lineWidth: !isNaN(parseInt(self.obj.lineWidth, 10)) ? parseInt(self.obj.lineWidth, 10) : 5,
|
||||
lineColor: isHexColor(self.obj.lineColor) ? self.obj.lineColor : "#000000",
|
||||
overflow: typeof self.obj.overflow === "boolean" ? self.obj.overflow : true,
|
||||
background: isHexColor(self.obj.background) ? self.obj.background : "#ffffff"
|
||||
}
|
||||
self.status = history
|
||||
self.step = -1
|
||||
self.firstStatus = ""
|
||||
|
||||
canvas = document.querySelector(self.option.el)
|
||||
if (!canvas || canvas.tagName !== "CANVAS") {
|
||||
throw new Error("Target element must be canvas")
|
||||
}
|
||||
|
||||
context = canvas.getContext("2d")
|
||||
canvas.style.backgroundColor = self.option.background
|
||||
canvas.style.touchAction = "none"
|
||||
|
||||
function syncHistoryIndex() {
|
||||
self.step = history.length - 1
|
||||
}
|
||||
|
||||
function clearCanvas() {
|
||||
context.clearRect(0, 0, canvas.width, canvas.height)
|
||||
}
|
||||
|
||||
function drawImage(dataUrl) {
|
||||
clearCanvas()
|
||||
if (!dataUrl) {
|
||||
return
|
||||
}
|
||||
var image = new Image()
|
||||
image.onload = function () {
|
||||
context.drawImage(image, 0, 0)
|
||||
}
|
||||
image.src = dataUrl
|
||||
}
|
||||
|
||||
function saveSnapshot() {
|
||||
var dataUrl = canvas.toDataURL("image/png")
|
||||
if (history.length === 0 || history[history.length - 1] !== dataUrl) {
|
||||
history.push(dataUrl)
|
||||
syncHistoryIndex()
|
||||
}
|
||||
}
|
||||
|
||||
function getPoint(event) {
|
||||
var source = event
|
||||
var rect = canvas.getBoundingClientRect()
|
||||
if (event.touches && event.touches.length > 0) {
|
||||
source = event.touches[0]
|
||||
} else if (event.changedTouches && event.changedTouches.length > 0) {
|
||||
source = event.changedTouches[0]
|
||||
}
|
||||
return {
|
||||
x: source.clientX - rect.left,
|
||||
y: source.clientY - rect.top
|
||||
}
|
||||
}
|
||||
|
||||
function preventDefault(event) {
|
||||
if (event && event.cancelable) {
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
function startDraw(event) {
|
||||
preventDefault(event)
|
||||
drawing = true
|
||||
currentPoint = getPoint(event)
|
||||
}
|
||||
|
||||
function moveDraw(event) {
|
||||
if (!drawing || !currentPoint) {
|
||||
return
|
||||
}
|
||||
preventDefault(event)
|
||||
var nextPoint = getPoint(event)
|
||||
context.beginPath()
|
||||
context.moveTo(currentPoint.x, currentPoint.y)
|
||||
context.lineTo(nextPoint.x, nextPoint.y)
|
||||
context.closePath()
|
||||
context.stroke()
|
||||
currentPoint = nextPoint
|
||||
}
|
||||
|
||||
function endDraw(event) {
|
||||
if (!drawing) {
|
||||
return
|
||||
}
|
||||
preventDefault(event)
|
||||
drawing = false
|
||||
currentPoint = null
|
||||
activePointerId = null
|
||||
saveSnapshot()
|
||||
}
|
||||
|
||||
// Prefer capability detection so Harmony / modern WebView devices do not rely on UA strings.
|
||||
function bindEvents() {
|
||||
if (window.PointerEvent) {
|
||||
canvas.addEventListener("pointerdown", function (event) {
|
||||
activePointerId = event.pointerId
|
||||
if (canvas.setPointerCapture) {
|
||||
canvas.setPointerCapture(event.pointerId)
|
||||
}
|
||||
startDraw(event)
|
||||
}, { passive: false })
|
||||
canvas.addEventListener("pointermove", function (event) {
|
||||
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
||||
return
|
||||
}
|
||||
moveDraw(event)
|
||||
}, { passive: false })
|
||||
canvas.addEventListener("pointerup", endDraw, { passive: false })
|
||||
canvas.addEventListener("pointercancel", endDraw, { passive: false })
|
||||
return
|
||||
}
|
||||
|
||||
if ("ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) {
|
||||
canvas.addEventListener("touchstart", startDraw, { passive: false })
|
||||
canvas.addEventListener("touchmove", moveDraw, { passive: false })
|
||||
canvas.addEventListener("touchend", endDraw, { passive: false })
|
||||
canvas.addEventListener("touchcancel", endDraw, { passive: false })
|
||||
return
|
||||
}
|
||||
|
||||
canvas.addEventListener("mousedown", startDraw, false)
|
||||
canvas.addEventListener("mousemove", moveDraw, false)
|
||||
canvas.addEventListener("mouseup", endDraw, false)
|
||||
canvas.addEventListener("mouseleave", endDraw, false)
|
||||
}
|
||||
|
||||
self.create = function (option) {
|
||||
var currentOption = option || self.option
|
||||
context.lineWidth = currentOption.lineWidth
|
||||
context.lineCap = "round"
|
||||
context.lineJoin = "round"
|
||||
context.strokeStyle = currentOption.lineColor
|
||||
if (currentOption.overflow === true && document.body) {
|
||||
document.body.style.overflow = "hidden"
|
||||
}
|
||||
self.firstStatus = canvas.toDataURL("image/png")
|
||||
history.length = 0
|
||||
history.push(self.firstStatus)
|
||||
syncHistoryIndex()
|
||||
bindEvents()
|
||||
}
|
||||
|
||||
self.getContentBase64 = function (rotate, callback) {
|
||||
if (!rotate) {
|
||||
var dataUrl = canvas.toDataURL("image/png")
|
||||
if (callback) {
|
||||
callback(dataUrl)
|
||||
}
|
||||
return dataUrl
|
||||
}
|
||||
|
||||
var tempCanvas = document.createElement("canvas")
|
||||
tempCanvas.width = canvas.offsetHeight || canvas.height
|
||||
tempCanvas.height = canvas.offsetWidth || canvas.width
|
||||
var tempContext = tempCanvas.getContext("2d")
|
||||
var image = new Image()
|
||||
image.onload = function () {
|
||||
var centerX = Math.round(tempCanvas.width / 2)
|
||||
var centerY = Math.round(tempCanvas.height / 2)
|
||||
tempContext.save()
|
||||
tempContext.translate(centerX, centerY)
|
||||
tempContext.rotate(-90 * Math.PI / 180)
|
||||
tempContext.drawImage(image, -image.width / 2, -image.height / 2)
|
||||
tempContext.restore()
|
||||
if (callback) {
|
||||
callback(tempCanvas.toDataURL("image/png"))
|
||||
}
|
||||
}
|
||||
image.src = self.getContentBase64(false)
|
||||
}
|
||||
|
||||
self.getBlob = function (dataUrl) {
|
||||
var content = dataUrl || self.getContentBase64()
|
||||
var parts = content.split(",")
|
||||
var mime = parts[0].match(/:(.*?);/)[1]
|
||||
var binary = atob(parts[1])
|
||||
var length = binary.length
|
||||
var bytes = new Uint8Array(length)
|
||||
while (length--) {
|
||||
bytes[length] = binary.charCodeAt(length)
|
||||
}
|
||||
return new Blob([bytes], { type: mime })
|
||||
}
|
||||
|
||||
self.getFile = function (fileName, dataUrl) {
|
||||
var content = dataUrl || self.getContentBase64()
|
||||
var name = fileName || "file"
|
||||
var parts = content.split(",")
|
||||
var mime = parts[0].match(/:(.*?);/)[1]
|
||||
var suffix = mime.split("/")[1]
|
||||
var binary = atob(parts[1])
|
||||
var length = binary.length
|
||||
var bytes = new Uint8Array(length)
|
||||
while (length--) {
|
||||
bytes[length] = binary.charCodeAt(length)
|
||||
}
|
||||
return new File([bytes], name + "." + suffix, { type: mime })
|
||||
}
|
||||
|
||||
self.reset = function () {
|
||||
if (!self.firstStatus) {
|
||||
return false
|
||||
}
|
||||
drawImage(self.firstStatus)
|
||||
history.length = 0
|
||||
history.push(self.firstStatus)
|
||||
syncHistoryIndex()
|
||||
return true
|
||||
}
|
||||
|
||||
self.undo = function (callback) {
|
||||
if (history.length <= 1 || self.step <= 0) {
|
||||
console.warn("no more undo")
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
return
|
||||
}
|
||||
self.step -= 1
|
||||
drawImage(history[self.step])
|
||||
}
|
||||
|
||||
self.redo = function (callback) {
|
||||
if (self.step >= history.length - 1) {
|
||||
console.warn("no more redo")
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
return
|
||||
}
|
||||
self.step += 1
|
||||
drawImage(history[self.step])
|
||||
}
|
||||
}
|
||||
|
||||
return Signature
|
||||
});
|
||||
Reference in New Issue
Block a user