Browse Source

签名板整合

yjf_v2
liwenxuan 2 years ago
parent
commit
800a6769e4
  1. BIN
      src/assets/paintboard.png
  2. 9
      src/components/DesignForm/assembly/index.ts
  3. 3
      src/components/DesignForm/public/form/formGroup.vue
  4. 17
      src/views/sysworkflow/codepage/page.vue
  5. 19
      src/views/sysworkflow/codepage/page_black.vue
  6. 2
      src/widget/index.ts
  7. 186
      src/widget/writingboard/index.vue
  8. 124
      src/widget/writingboard/paintBoard.vue
  9. 713
      src/widget/writingboard/vueSignature.vue

BIN
src/assets/paintboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

9
src/components/DesignForm/assembly/index.ts

@ -246,6 +246,15 @@ const selectOption: any = [
control: { control: {
}, },
config: {} config: {}
},
{
type: 'signaturemap',
label: '签名板',
icon: 'faedit',
iconFont: 'fa-edit',
control: {
},
config: {}
} }
] ]
}, },

3
src/components/DesignForm/public/form/formGroup.vue

@ -426,6 +426,7 @@ onMounted(()=>{
</div> </div>
</template> </template>
<SignatureMap v-else-if="element.type === 'signaturemap'" :data="element" />
<OrgCentent v-else-if="element.type === 'orgCentent'" :data="element" /> <OrgCentent v-else-if="element.type === 'orgCentent'" :data="element" />
<BaiduMap v-else-if="element.type === 'baidumap'" :data="element" /> <BaiduMap v-else-if="element.type === 'baidumap'" :data="element" />
<OrgCitys v-else-if="element.type === 'organization'" :data="element" /> <OrgCitys v-else-if="element.type === 'organization'" :data="element" />
@ -433,7 +434,7 @@ onMounted(()=>{
<SerialNumber v-else-if="element.type === 'serialNumber'" :data="element" :tablekey="props.tableinfo.name" :numrun="props.numrun" /> <SerialNumber v-else-if="element.type === 'serialNumber'" :data="element" :tablekey="props.tableinfo.name" :numrun="props.numrun" />
<!--其他组件--> <!--其他组件-->
<FormItem v-else :data="element" /> <FormItem v-else :data="element" />
<!--组件设计外功能框架--> <!--组件设计外功能框架-->
<template v-if="type === 5"> <template v-if="type === 5">
<div class="drag-control"> <div class="drag-control">

17
src/views/sysworkflow/codepage/page.vue

@ -4,16 +4,17 @@
@ 备注: @ 备注:
--> -->
<template> <template>
<baidu-map class="map" ak="ljiKlTAsS7SNVqDM16IUwRVFFhrvbxiF" v="3.0" :center="{lng: 116.404, lat: 39.915}" :zoom="15" :scroll-wheel-zoom="true"> <SignatureMap />
<bm-map-type :map-types="['BMAP_NORMAL_MAP', 'BMAP_HYBRID_MAP']" anchor="BMAP_ANCHOR_TOP_LEFT"></bm-map-type> <PaintBoard @updataconbt="qianming" />
</baidu-map>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { BaiduMap } from 'vue-baidu-map-3x' import PaintBoard from '@/views/knowledge/news/paintBoard.vue';
const qianming = (val:any) =>{
console.log("图片回传--->",val)
}
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.map {
width: 100%;
height: calc(100vh - 90px);
}
</style> </style>

19
src/views/sysworkflow/codepage/page_black.vue

@ -0,0 +1,19 @@
<!--
@ 作者: 秦东
@ 时间: 2023-12-07 16:49:57
@ 备注:
-->
<template>
<baidu-map class="map" ak="ljiKlTAsS7SNVqDM16IUwRVFFhrvbxiF" v="3.0" :center="{lng: 116.404, lat: 39.915}" :zoom="15" :scroll-wheel-zoom="true">
<bm-map-type :map-types="['BMAP_NORMAL_MAP', 'BMAP_HYBRID_MAP']" anchor="BMAP_ANCHOR_TOP_LEFT"></bm-map-type>
</baidu-map>
</template>
<script lang='ts' setup>
import { BaiduMap } from 'vue-baidu-map-3x'
</script>
<style lang='scss' scoped>
.map {
width: 100%;
height: calc(100vh - 90px);
}
</style>

2
src/widget/index.ts

@ -6,6 +6,7 @@ import urlLink from './urllink/index.vue'
import orgCitys from './orgcitys/index.vue' import orgCitys from './orgcitys/index.vue'
import baiduMap from './baidumap/index.vue' import baiduMap from './baidumap/index.vue'
import orgCentent from './org/index.vue' import orgCentent from './org/index.vue'
import signatureMap from './writingboard/index.vue'
export default (app: any) => { export default (app: any) => {
app.component('SerialNumber', serialNumber) app.component('SerialNumber', serialNumber)
@ -13,4 +14,5 @@ export default (app: any) => {
app.component('OrgCitys', orgCitys) app.component('OrgCitys', orgCitys)
app.component('BaiduMap', baiduMap) app.component('BaiduMap', baiduMap)
app.component('OrgCentent', orgCentent) app.component('OrgCentent', orgCentent)
app.component('SignatureMap', signatureMap)
} }

186
src/widget/writingboard/index.vue

@ -0,0 +1,186 @@
<!--
@ 作者: 秦东
@ 时间: 2023-12-08 16:49:57
@ 备注:
-->
<template>
<el-form-item
v-bind="data.item"
:prop="tProp || data.name"
:class="config.className"
:rules="itemRules as any"
:label="getLabel(data.item as FormItem)"
>
<input v-model="value" type="hidden" >
</el-form-item>
<PaintBoard @updataconbt="qianming" />
</template>
<script lang='ts' setup>
import PaintBoard from './paintBoard.vue';
import {
constControlChange,
constFormProps,
} from '@/api/DesignForm/utils'
import validate from '@/api/DesignForm/validate'
import { FormItem, FormList } from '@/api/DesignForm/types'
const props = withDefaults(
defineProps<{
data: FormList
tablekey: any
numrun?: number
modelValue?: any //
tProp?: string // form-itemprop
}>(),
{}
)
const emits = defineEmits<{
(e: 'update:modelValue', numVal: any): void
}>()
const formProps = inject(constFormProps, {}) as any
const type = computed(() => {
return formProps.value.type
})
const config = computed(() => {
return props.data.config || {}
})
const changeEvent = inject(constControlChange, '') as any
const value = computed({
get() {
if (props.tProp) {
//
return props.modelValue
} else {
return formProps.value.model[props.data.name]
}
},
set(newVal: any) {
if (props.tProp) {
emits('update:modelValue', newVal)
}
updateModel(newVal)
}
})
const updateModel = (val: any) => {
let controlAttribute = ""
if(props.data.control){
if(props.data.control.type){
controlAttribute = props.data.control.type
}
}
changeEvent &&
changeEvent({
key: props.data.name,
value: val,
data: props.data,
tProp: props.tProp,
type: props.data.type,
attribute: controlAttribute
})
}
const getLabel = (ele: FormItem) => {
const showColon = formProps.value.showColon ? ':' : ''
if (ele) {
return ele.showLabel ? '' : ele.label + showColon
} else {
return ''
}
}
// item
const itemRules = computed(() => {
let temp
const itemR: any = props.data.item?.rules || []
const customR = formatCustomRules()
// undefined
if (itemR?.length || customR?.length) {
temp = [...customR, ...itemR]
}
return temp
})
// customRulesrules
const formatCustomRules = () => {
const rulesReg: any = {}
validate &&
validate.forEach(item => {
rulesReg[item.type] = item.regExp
})
// 使provide
const temp: any = []
props.data.customRules?.forEach((item: any) => {
if (!item.message && item.type !== 'methods') {
return //
}
let obj = {}
if (item.type === 'required') {
obj = { required: true }
} else if (item.type === 'rules') {
//
obj = { pattern: item.rules }
} else if (item.type === 'methods') {
//
const methods: any = item.methods
if (methods) {
obj = { validator: inject(methods, {}) }
}
} else if (item.type) {
obj = { pattern: rulesReg[item.type as string] }
}
// push
let message: any = { message: item.message }
if (!item.message) {
// 使validatormessage使 callback(new Error('x'));
message = {}
}
temp.push(
Object.assign(
{
trigger: item.trigger || 'blur'
},
obj,
message
)
)
})
return temp
}
const qianming = (val:any) =>{
console.log("图片回传--->",val)
value.value = val
}
</script>
<style lang='scss' scoped>
.imgbox{
padding: 0 5px;
max-width: 300px;
max-height: 200px;
width: 100%;
height: 200px;
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: var(--el-fill-color-light);
color: var(--el-text-color-secondary);
font-size: 30px;
}
}
</style>

124
src/widget/writingboard/paintBoard.vue

@ -0,0 +1,124 @@
<template>
<div >
<div v-show="pantareaisShow" id="canvasWrap" style="width:100%;">
<vueOnlineSignature ref="vueSignatureRef" v-bind="params"/>
</div>
<img v-if="imagesSRC" :src="imagesSRC" alt="" style="max-width: 100%">
<div class="buttonList" >
<div class="button" @click="confirm">签名完成</div>
<div class="button" @click="reset">重签</div>
</div>
</div>
</template>
<script setup lang="ts">
import vueOnlineSignature from '@/widget/writingboard/vueSignature.vue';
import { ref, reactive } from 'vue'
const pantareaisShow = ref<boolean>(true)
const params = reactive<any>({
width: 751,// 1px,1px
height: 301,//
lineWidth: 5,
lineColor: '#000',
canvasBack: new URL('@/assets/paintboard.png', import.meta.url).href,//
isCrop: true,
edg: 0,
fullScreen: false,
domId: '',
imgType: 'image/png',
imgBack: new URL('@/assets/paintboard.png', import.meta.url).href,//
isRepeat: '',
noRotation: false,
backIsCenter: false,
verticalDeductWidth: 10,
verticalDeductHeight: 24,
acrossDeductWidth: 30,
acrossDeductHeight: 20,
recoverPoints: [],
isBrush: false,
brushLine: 20
})
const emits = defineEmits(["updataconbt"]);
let vueSignatureRef = ref<any>(null)
const imagesSRC = ref<string>('')
const confirm = () => {
vueSignatureRef.value.confirm()
.then((res:{base64: string, points: any}) => {
imagesSRC.value = res.base64
sessionStorage.setItem('points', JSON.stringify(res.points))
pantareaisShow.value = false
emits("updataconbt",res.base64)
})
.catch(() => {
alert('未曾签名')
})
}
const reset = () => {
imagesSRC.value = ''
pantareaisShow.value = true
if(vueSignatureRef.value != null){
vueSignatureRef.value.reset()
}
}
</script>
<style lang="less" scoped>
#canvasWrap{
margin: 1px 0;
}
canvas{
border: 1px dashed #ccc
}
.input__wrap{
list-style-type: none;
width: 100%;
padding: 0;
li{
line-height: 30px;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
}
span{
width: 130px;
display: inline-block;
text-align: right;
margin-right: 10px
}
input[type="checkbox"]{
margin-left: 0
}
p{
margin: 0 0 10px 140px;
color:#aaa
}
}
.button{
width: 290px;
height: 35px;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
}
.buttonList{
display: flex;
.button ~ .button{
margin-left: 10px;
}
}
</style>

713
src/widget/writingboard/vueSignature.vue

@ -0,0 +1,713 @@
<template>
<canvas v-if="esignReset" ref="canvasRef" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"></canvas>
<!-- <img v-show="false" ref="penRef" :src="penImg" > -->
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed, onMounted, nextTick, onBeforeMount, onUnmounted, toRaw } from 'vue'
const emits = defineEmits(['onDrawingStatus', 'onMouseDown', 'onMouseMove', 'onMouseUp', 'onTouchStart', 'onTouchMove', 'onTouchEnd'])
interface pointsType {
x: number,
y: number,
direction: string
}
interface Props {
width?: number,
height?: number,
lineWidth?: number,
lineColor?: string,
canvasBack?: string,
isCrop?: boolean,
edg?: number,
fullScreen?: boolean,
domId?: string,
imgBack?: string,
isRepeat?: string,
noRotation?: boolean,
imgType?: string,
backIsCenter?: boolean,
acrossDeductWidth?: number,
acrossDeductHeight?: number
verticalDeductWidth?: number,
verticalDeductHeight?: number,
recoverPoints?: pointsType[],
isBrush?: boolean,
brushLine?: number
}
const props = withDefaults(defineProps<Props>(), {
width: 0, // ()
height: 0, //
lineWidth: 8, //
lineColor: '#000000', //
canvasBack: '', // '#ccc''#E5A1A1''rgb(229, 161, 161)''rgba(0,0,0,.6)''red', 'http''https''base64'
isCrop: false, //
edg: 0, // ,90270,
fullScreen: false, //
domId: '', // 使canvasID, width
imgBack: '', //canvasBack '#ccc''#E5A1A1''rgb(229, 161, 161)''rgba(0,0,0,.6)''red', 'http''https''base64'
isRepeat: '', // (:'repeat','repeat-x','repeat-y' )
noRotation: false, // (true)
imgType: 'image/png', // 'image/jpeg'
backIsCenter: false, // (使domIdcanvas)
verticalDeductWidth: 0, //
verticalDeductHeight: 0, //
acrossDeductWidth: 0, //
acrossDeductHeight: 0, //
recoverPoints: () => [], // canvasconfirm[{x:0,y:0,direction:'across'}], directionacrossvertical
isBrush: false, // 使imgBack
brushLine: 20 // 线20isBrushtrue
})
const hasDrew = ref<boolean>(false)
const isOrientationchange = ref<boolean>(false)
const esignReset = ref<boolean>(true)
const resultImg = ref<string>('')
const points = ref<any[]>([])
let canvasTxt = ref<CanvasRenderingContext2D | null>(null)
let canvasRef = ref<HTMLCanvasElement | null>(null)
let cropCanvas = ref<HTMLCanvasElement | null>(null)
let cropCanvasTxt = ref<CanvasRenderingContext2D | null>(null)
const startX = ref<number>(0)
const startY = ref<number>(0)
const sratio = ref<number>(1)
const isDrawing = ref<boolean>(false)
const isLoad = ref<boolean>(false)
let imgBackDom = ref<any>(null)
let canvasBackDom = ref<any>(null)
let screenPatams = reactive<{ width:number, height: number }>({
width: 0,
height: 0
})
let domPatams = reactive<{ width:number, height: number }>({
width: 0,
height: 0
})
// --------------------------------
const hasPoints = ref<any[]>([])
const pointsArr = ref<any[]>([])
const smoothness = ref<number>(80)
const l = ref<number>(props.brushLine < 20 ? 20 : props.brushLine)
//const penImg = new URL('@/assets/pen2.png', import.meta.url).href
let penRef = ref<any>(null)
// --------------------------------
const ratio = computed(() => (domPatams.height ? domPatams.height : props.fullScreen ? screenPatams.height : props.height) / (domPatams.width ? domPatams.width : props.fullScreen ? screenPatams.width : props.width) )
const canvasBackground = computed(() => props.canvasBack ? props.canvasBack : 'rgba(255, 255, 255, 0)' )
watch(canvasBackground, async (newVal: string) => {
await nextTick()
canvasRef.value && (canvasRef.value.style.background = newVal)
})
watch(hasDrew, (newVal: boolean) => {
emits('onDrawingStatus', newVal)
})
const getSizeRatio = () => {
return !props.fullScreen && props.backIsCenter
}
const setCanvasImageBack = (status: any) => {
const canvas = canvasRef.value as HTMLCanvasElement
let pat = canvasTxt.value?.createPattern(canvasBackDom.value, (props.isRepeat || "no-repeat"));
canvasTxt.value?.rect(0,0,canvas.width ,canvas.height)
canvasTxt!.value!.fillStyle = (pat as any);
canvasTxt.value?.fill();
if (status) {
autoDraw(null, null)
}
}
const setCanvasBack = (status: any) => {
const canvas = canvasRef.value as HTMLCanvasElement
if (props.canvasBack && canvasBackDom.value && isImgaes(props.canvasBack)) {
setCanvasImageBack(status)
} else {
canvas.style.background = canvasBackground.value
}
}
const getDomSize = () => {
const canvas = canvasRef.value as HTMLCanvasElement
if (props.domId) {
let dom = document.getElementById(props.domId)
let domWidth = dom ? dom.clientWidth || dom.offsetWidth : props.fullScreen ? screenPatams.width : props.width
let domHeight = dom ? dom.clientHeight || dom.offsetHeight : props.fullScreen ? screenPatams.height : props.height
canvas.height = domHeight
canvas.width = domWidth
domPatams.width = domWidth
domPatams.height = domHeight
} else {
canvas.height = props.fullScreen ? screenPatams.height : props.height
canvas.width = props.fullScreen ? screenPatams.width : props.width
}
}
const resizeHandler = (status: any) => {
if (isOrientationchange.value) return false
const canvas = canvasRef.value as HTMLCanvasElement
canvas.style.width = (domPatams.width ? domPatams.width : props.fullScreen ? screenPatams.width : props.width) + "px"
const realw = parseFloat(window.getComputedStyle(canvas).width)
canvas.style.height = ratio.value * realw + "px";
canvasTxt.value = canvas.getContext('2d')
canvasTxt.value?.scale(1 * sratio.value, 1 * sratio.value)
sratio.value = realw / (domPatams.width ? domPatams.width : props.fullScreen ? screenPatams.width : props.width)
canvasTxt.value?.scale(1 / sratio.value, 1 / sratio.value)
if (props.canvasBack) {
let IntervaId = setInterval(() => {
if ((canvasBackDom.value && isLoad.value) || !isImgaes(props.canvasBack)) {
setCanvasBack(status)
clearInterval(IntervaId)
}
}, 100)
} else {
if (status) {
autoDraw(null, null)
}
}
}
const orientationchangeEvent = () => {
let directionWidth = window.orientation == 0 || window.orientation == 180 ? props.verticalDeductWidth : props.acrossDeductWidth
let directionHeight = window.orientation == 0 || window.orientation == 180 ? props.verticalDeductHeight : props.acrossDeductHeight
screenPatams.width = window.navigator.platform.indexOf('Win') || window.navigator.platform.indexOf('Mac') ? (document.body.clientHeight || document.body.offsetHeight) - directionWidth : (document.body.clientWidth || document.body.offsetWidth) - directionWidth
screenPatams.height = window.navigator.platform.indexOf('Win') || window.navigator.platform.indexOf('Mac') ? (document.body.clientWidth || document.body.offsetWidth) - directionHeight : (document.body.clientHeight || document.body.offsetHeight) - directionHeight
getImages()
isOrientationchange.value = true
esignReset.value = false
let setIntervalId = setInterval(async() => {
if (isLoad.value) {
clearInterval(setIntervalId)
esignReset.value = true
isOrientationchange.value = false
await nextTick()
getDomSize()
resizeHandler(true)
}
}, 100)
}
const isImgaes = (params: string) => {
let imgType = ['.jpeg', '.bmp', '.jpg', '.gif', '.webp', '.pcx', '.tif', '.tga', '.exif', '.fpx', '.svg', '.cdr', '.pcd', '.dxf', '.ufo', '.eps', '.ai', '.png', '.hdri', '.raw', '.wmf', '.flic', '.emf', '.ico', '.avif', '.apng']
let regex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*?)\s*$/i;
let status = params.includes('http://') || params.includes('https://') || regex.test(params) || imgType.some(item => params.includes(item))
return status
}
const rotateBase64Img = (src: string, edg: number, type: string = 'not') => {
return new Promise((resolve, reject) => {
let canvas: HTMLCanvasElement = document.createElement("canvas");
let ctx = canvas.getContext("2d") as CanvasRenderingContext2D
let imgW;//
let imgH;//
let size;//canvas
if (edg % 90 != 0) {
reject("旋转角度必须是90的倍数!");
throw '旋转角度必须是90的倍数!';
}
(edg < 0) && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4; //
const cutCoor = {sx: 0, sy: 0, ex: 0, ey: 0}; //
let image = new Image();
image.crossOrigin = "anonymous"
image.src = src;
image.onload = function () {
imgW = image.width;
imgH = image.height;
//console.log(imgH, 'imgH')
size = imgW > imgH ? imgW : imgH;
canvas.width = size * 2;
canvas.height = size * 2;
let Cwidth = domPatams.width ? domPatams.width : props.fullScreen ? screenPatams.width : props.width
let ratio = getSizeRatio() && type == 'init'
switch (quadrant) {
case 0:
cutCoor.sx = getSizeRatio() && type == 'init' && imgW > screenPatams.width ? size - ((imgW - (getDirection() == 'across' ? screenPatams.width : screenPatams.height)) / 2) : size
cutCoor.sy = size;
cutCoor.ex = size + imgW;
cutCoor.ey = size + imgH;
break;
case 1:
cutCoor.sx = ratio ? size - props.height : window.orientation == 0 || window.orientation == 180 ? size - Cwidth : size - imgH
cutCoor.sy = size
cutCoor.ex = size;
cutCoor.ey = size + imgW;
break;
case 2:
cutCoor.sx = size - imgW;
cutCoor.sy = size - imgH;
cutCoor.ex = size;
cutCoor.ey = size;
break;
case 3:
cutCoor.sx = size;
cutCoor.sy = size - imgW;
cutCoor.ex = size + imgH;
cutCoor.ey = size + imgW;
break;
}
ctx.translate(size, size);
ctx.rotate(edg * Math.PI / 180);
ctx.drawImage(image, 0, 0);
var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey);
if (quadrant % 2 == 0) {
canvas.width = imgW;
canvas.height = imgH;
} else {
canvas.width = imgH;
canvas.height = imgW;
}
//putImageData()
ctx.putImageData(imgData, 0, 0);
resolve(canvas.toDataURL(props.imgType))
}
})
}
const getImages = async () => {
isLoad.value = false
let edg = window.orientation == 0 || window.orientation == 180 ? 90 : 0
let ratio = props.fullScreen ? edg : 0
if (isImgaes(props.imgBack)) {
let res = await rotateBase64Img(props.imgBack, ratio, 'init')
if (res) {
imgBackDom.value = new Image();
imgBackDom.value.crossOrigin = "anonymous"
imgBackDom!.value!.src = res;
}
}
if (isImgaes(props.canvasBack)){
let res = await rotateBase64Img(props.canvasBack, ratio, 'init')
if (res) {
canvasBackDom.value = new Image();
canvasBackDom.value.crossOrigin = "anonymous"
canvasBackDom!.value!.src = res;
canvasBackDom!.value.onload = () => {
isLoad.value = true
}
}
}
}
onMounted(() => {
//
let directionWidth = window.orientation == 0 || window.orientation == 180 ? props.verticalDeductWidth : props.acrossDeductWidth
//
let directionHeight = window.orientation == 0 || window.orientation == 180 ? props.verticalDeductHeight : props.acrossDeductHeight
screenPatams.width = (document.body.clientWidth || document.body.offsetWidth) - directionWidth
screenPatams.height = (document.body.clientHeight || document.body.offsetHeight) - directionHeight
getImages()
getDomSize()
window.addEventListener("orientationchange", orientationchangeEvent)
resizeHandler(props.recoverPoints && props.recoverPoints.length && !props.isBrush ? true : false)
//
document.onmouseup= () => {
isDrawing.value = false
}
})
const getDirection = () => {
return window.orientation == 90 || window.orientation == -90 ? 'across' : 'vertical'
}
// ----------------------------------------------------------------
const distance = (a: {x:number, y:number}, b: {x:number, y:number}) => {
let x = b.x - a.x , y = b.y - a.y;
return Math.sqrt(x*x+y*y);
}
const customMouseDown = (e: {x:number, y:number, direction: string}) => {
hasPoints.value = []
startX.value = e.x
startY.value = e.y
pointsArr.value.unshift(e);
}
const customMouseMove = (e: {x:number, y:number, direction: string}) => {
let of = e; //move
let up = {
x: startX.value,
y: startY.value,
} //down
hasPoints.value.unshift({time:new Date().getTime() ,dis: distance(up,of)});
let dis = 0;
for (let n = 0; n < hasPoints.value.length-1; n++) {
dis += hasPoints.value[n].dis;
if (dis > smoothness.value)
break;
}
startX.value = of.x;
startY.value = of.y;
let len = Math.round(hasPoints.value[0].dis/2)+1;
for (let i = 0; i < len; i++) {
let x = up.x + (of.x-up.x)/len*i;
let y = up.y + (of.y-up.y)/len*i;
canvasTxt.value?.beginPath();
x = x-l.value /2;
y = y - l.value /2;
pointsArr.value.unshift({x,y,direction: e.direction});
canvasTxt.value?.drawImage(penRef.value,x,y,l.value ,l.value );
l.value = l.value - 0.2;
if( l.value < 10) l.value = 10;
}
}
const customMouseUp = () => {
l.value = props.brushLine < 20 ? 20 : props.brushLine;
if(pointsArr.value.length > 100){
for(var j = 0; j <60 ;j++){
pointsArr.value[j].x = pointsArr.value[j].x-l.value/4;
pointsArr.value[j].y = pointsArr.value[j].y - l.value/4;
canvasTxt.value?.drawImage(penRef.value,pointsArr.value[j].x,pointsArr.value[j].y,l.value,l.value);
l.value = l.value - 0.3;
if( l.value < 5) l.value = 5;
}
l.value = props.brushLine < 20 ? 20 : props.brushLine;
pointsArr.value = [];
}
if (pointsArr.value.length==1) {
canvasTxt.value?.drawImage(penRef.value,pointsArr.value[0].x - l.value/2,pointsArr.value[0].y - l.value/2,l.value,l.value);
pointsArr.value = [];
}
}
// ----------------------------------------------------------------
// pc
const onMouseDown = (e: any) => {
e = e || event
e.preventDefault()
isDrawing.value = true
hasDrew.value = true
let params = {
x: e.offsetX,
y: e.offsetY,
direction: getDirection()
}
// ---------------------------------
if (props.isBrush) {
customMouseDown(params)
} else {
drawStart(params)
}
// ---------------------------------
emits('onMouseDown', e)
}
const onMouseMove = (e: any) => {
e = e || event
e.preventDefault()
if (isDrawing.value) {
let obj = {
x: e.offsetX,
y: e.offsetY,
direction: getDirection()
}
// ---------------------------------
if (props.isBrush) {
customMouseMove(obj)
} else {
drawMove(obj)
}
// ---------------------------------
}
emits('onMouseMove', e)
}
const onMouseUp = (e: any) => {
e = e || event
e.preventDefault()
let obj = {
x: e.offsetX,
y: e.offsetY,
direction: getDirection()
}
if (props.isBrush) {
customMouseUp()
} else {
drawEnd(obj)
}
isDrawing.value = false
emits('onMouseUp', e)
}
// mobile
const onTouchStart = (e: any) => {
e = e || event
e.preventDefault()
hasDrew.value = true
if (e.touches.length === 1) {
let canvas = canvasRef.value as HTMLCanvasElement
let obj = {
x: e.targetTouches[0].clientX - canvas.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.getBoundingClientRect().top,
direction: getDirection()
}
// ---------------------------------
if (props.isBrush) {
customMouseDown(obj)
} else {
drawStart(obj)
}
// ---------------------------------
}
emits('onTouchStart', e)
}
const onTouchMove = (e: any) => {
e = e || event
e.preventDefault()
if (e.touches.length >= 1) {
let canvas = canvasRef.value as HTMLCanvasElement
let obj = {
x: e.targetTouches[0].clientX - canvas.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.getBoundingClientRect().top,
direction: getDirection()
}
// ---------------------------------
if (props.isBrush) {
customMouseMove(obj)
} else {
drawMove(obj)
}
// ---------------------------------
}
emits('onTouchMove', e)
}
const onTouchEnd = (e: any) => {
e = e || event
e.preventDefault()
console.log(e.touches, 'e.touches')
if (e.touches.length === 1) {
let canvas = canvasRef.value as HTMLCanvasElement
let obj = {
x: e.targetTouches[0].clientX - canvas.getBoundingClientRect().left,
y: e.targetTouches[0].clientY - canvas.getBoundingClientRect().top,
direction: getDirection()
}
// ---------------------------------
if (props.isBrush) {
customMouseUp()
} else {
drawEnd(obj)
}
// ---------------------------------
} else {
if (props.isBrush) {
customMouseUp()
} else {
points.value.push({x: -1, y: -1, direction: getDirection()})
}
}
emits('onTouchEnd', e)
}
//
const drawStart = (params: { x: number, y: number}) => {
startX.value = params.x
startY.value = params.y
canvasTxt.value?.beginPath()
canvasTxt.value?.moveTo(startX.value, startY.value)
canvasTxt.value?.lineTo(params.x, params.y)
canvasTxt!.value!.lineCap = 'round'
canvasTxt!.value!.lineJoin = 'round'
canvasTxt!.value!.lineWidth = props.lineWidth * sratio.value
canvasTxt.value?.stroke()
canvasTxt.value?.closePath()
points.value.push(params)
}
const drawMove = (params: { x: number, y: number}) => {
canvasTxt.value?.beginPath()
canvasTxt.value?.moveTo(startX.value, startY.value)
canvasTxt.value?.lineTo(params.x, params.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 = params.y
startX.value = params.x
points.value.push(params)
}
const drawEnd = (params: { x: number, y: number}) => {
canvasTxt.value?.beginPath()
canvasTxt.value?.moveTo(startX.value, startY.value)
canvasTxt.value?.lineTo(params.x, params.y)
canvasTxt!.value!.lineCap = 'round'
canvasTxt!.value!.lineJoin = 'round'
canvasTxt.value?.stroke()
canvasTxt.value?.closePath()
points.value.push(params)
points.value.push({x: -1, y: -1})
}
const autoDraw = (canvasRefs: HTMLCanvasElement | null, canvas2d: CanvasRenderingContext2D | null) => {
if ((points.value && points.value.length || props.recoverPoints && props.recoverPoints.length) && !props.isBrush) {
let canvas = canvasRefs || canvasRef.value as HTMLCanvasElement
let canvasText = canvas2d || canvasTxt.value
let pointsList = props.recoverPoints && props.recoverPoints.length ? props.recoverPoints : points.value
if (pointsList && pointsList.length) {
hasDrew.value = true
}
pointsList.reduce((acc, cur) => {
if (cur.x != -1 && cur.y != -1 && acc.x != -1 && acc.y != -1) {
canvasText?.beginPath()
let position = { accX: acc.x, accY: acc.y, curX: cur.x, curY: cur.y }
if (props.fullScreen) {
if ((window.orientation == 0 || window.orientation == 180) && acc.direction == 'across' && cur.direction == 'across') { //
position = { accX: canvas.width - acc.y, accY: acc.x, curX: canvas.width - cur.y, curY: cur.x }
} else if ((window.orientation == 90 || window.orientation == -90) && acc.direction == 'vertical' && cur.direction == 'vertical') { //
position = { accX: acc.y, accY: canvas.height - acc.x, curX: cur.y, curY: canvas.height - cur.x }
}
}
canvasText!.moveTo(position.accX, position.accY)
canvasText!.lineTo(position.curX, position.curY)
canvasText!.strokeStyle = props.lineColor
canvasText!.lineWidth = props.lineWidth * sratio.value
canvasText!.lineCap = 'round'
canvasText!.lineJoin = 'round'
canvasText!.stroke()
canvasText!.closePath()
}
return cur
})
}
}
//
const confirm = () => {
return new Promise((resolve, reject) => {
if (!hasDrew.value) {
reject(`Warning: Not Signned!`)
return
}
let canvas = canvasRef.value as HTMLCanvasElement
let resImgData = (canvasTxt.value as CanvasRenderingContext2D).getImageData(0, 0, canvas.width, canvas.height)
canvasTxt!.value!.globalCompositeOperation = "destination-over"
if (props.canvasBack && props.imgBack && !props.isBrush) {
canvasTxt.value?.clearRect(0,0,canvas.width ,canvas.height);
autoDraw(null, null)
}
// canvas
if (props.imgBack && isImgaes(props.imgBack) && !props.isBrush){
let pat = canvasTxt.value?.createPattern(imgBackDom.value, (props.isRepeat || "no-repeat"));
canvasTxt.value?.rect(0,0,canvas.width ,canvas.height);
canvasTxt!.value!.fillStyle = (pat as any);
canvasTxt.value?.fill();
} else if(props.imgBack && !isImgaes(props.imgBack) && !props.isBrush) {
canvasTxt!.value!.fillStyle = props.imgBack;
canvasTxt.value?.fillRect(0,0, canvas.width, canvas.height);
}
resultImg.value = canvas.toDataURL()
let resultImgs:any = resultImg.value
canvasTxt.value?.clearRect(0, 0, canvas.width ,canvas.height)
canvasTxt.value?.putImageData(resImgData, 0, 0)
canvasTxt!.value!.globalCompositeOperation = "source-over"
if (props.isCrop) {
const crop_area = getCropArea(resImgData.data) as [number, number, number,number]
let crop_canvas: HTMLCanvasElement | null = 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 = (cropCanvasTxt.value || canvasTxt.value)?.getImageData(...crop_area)
//const crop_imgData = (cropCanvasTxt.value || canvasTxt.value)?.getImageData.apply(null, crop_area)
crop_ctx!.globalCompositeOperation = "destination-over"
crop_ctx?.putImageData(crop_imgData!, 0, 0)
resultImgs = crop_canvas.toDataURL()
crop_canvas = null
}
let edg = (props.fullScreen && ((window.orientation == 0 || window.orientation == 180) || ((window.orientation == 90 || window.orientation == -90) && !props.noRotation))) || (window.orientation === undefined) && props.noRotation ? props.edg : 0
rotateBase64Img(resultImgs, edg)
.then(base64 => {
resolve({
base64,
points: points.value
})
})
})
}
const reset = () => {
let canvas = canvasRef.value as HTMLCanvasElement
canvasTxt.value?.clearRect(
0,
0,
canvas.width,
canvas.height
)
points.value = []
hasDrew.value = false
resultImg.value = ''
setCanvasBack(false)
}
const getCropArea = (imgData: any) => {
if (props.imgBack && !props.isBrush) {
cropCanvas.value = document.createElement('canvas')
if (props.domId) {
let dom = document.getElementById(props.domId)
let domWidth = dom ? dom.clientWidth || dom.offsetWidth : props.fullScreen ? screenPatams.width : props.width
let domHeight = dom ? dom.clientHeight || dom.offsetHeight : props.fullScreen ? screenPatams.height : props.height
cropCanvas.value.height = domHeight
cropCanvas.value.width = domWidth
domPatams.width = domWidth
domPatams.height = domHeight
} else {
cropCanvas.value.height = props.fullScreen ? screenPatams.height : props.height
cropCanvas.value.width = props.fullScreen ? screenPatams.width : props.width
}
cropCanvasTxt.value = cropCanvas.value.getContext('2d')
if (isImgaes(props.imgBack)){
let pat = cropCanvasTxt.value?.createPattern(imgBackDom.value, (props.isRepeat || "no-repeat"));
cropCanvasTxt.value?.rect(0,0,cropCanvas.value.width ,cropCanvas.value.height);
cropCanvasTxt!.value!.fillStyle = (pat as any);
cropCanvasTxt.value?.fill();
} else if(!isImgaes(props.imgBack)) {
cropCanvasTxt!.value!.fillStyle = props.imgBack;
cropCanvasTxt.value?.fillRect(0,0, cropCanvas.value.width, cropCanvas.value.height);
}
autoDraw(cropCanvas.value, cropCanvasTxt.value)
}
let canvas = cropCanvas.value as HTMLCanvasElement || canvasRef.value as HTMLCanvasElement
let topX = canvas.width;
var btmX = 0;
var topY = canvas.height;
var btnY = 0
for (var i = 0; i < canvas.width; i++) {
for (var j = 0; j < canvas.height; j++) {
var pos = (i + canvas.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
}
const recoverDraw = (pointsList: pointsType[]) => {
if (props.isBrush) return false
let canvas = canvasRef.value as HTMLCanvasElement
canvasTxt.value?.clearRect(
0,
0,
canvas.width,
canvas.height
)
points.value = pointsList
hasDrew.value = true
resultImg.value = ''
setCanvasBack(true)
}
onBeforeMount(() => {
if (props.fullScreen) {
// let bodyDom = document.getElementsByTagName('body')
// bodyDom[0].style = 'height: 100vh';
document.body.style.height = '100vh';
}
window.addEventListener('resize', resizeHandler)
})
onUnmounted(() => {
if (props.fullScreen) {
// let bodyDom = document.getElementsByTagName('body')
// bodyDom[0].style = '';
document.body.style.height = '';
}
window.removeEventListener('resize', resizeHandler)
window.removeEventListener("orientationchange", orientationchangeEvent)
})
defineExpose({
confirm: toRaw(confirm),
reset,
recoverDraw
})
</script>
<style scoped>
canvas {
max-width: 100%;
display: block;
}
</style>
Loading…
Cancel
Save