改写成了uniapp通用组件
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
@success | Events | 否 | 成功回调 |
@fail | Events | 否 | 失败回调 |
data | Array | 是 | 用来匹配。 |
-
事件回调 返回一个对象
obj
名称 | 类型 | 内容 | 说明 |
---|---|---|---|
msg | String | seal:ok或seal:no | 消息 |
likeness | Number | 相似度 | |
location | Array | 触发的位置 |
注意-
-
location并不会大于传入
data
的长度 -
当likeness大于或等于
90
才触发success
js另写了一个文件
<template>
<view class="seal" @touchstart="touchstart" @touchend="touchEnd" />
</template>
<script src="./seal.js" />
<style lang="scss" scoped>
.seal{
100%;
height: 100%;
}
</style>
- script
let log=console.log;
export default {
props:{
data:Array
},
data() {
let Old=JSON.parse(JSON.stringify(this.data));
let Dot=this.data.length; //点的个数
return {
array:{
New:[],
Old,
Dot,
},
}
},
methods: {
touchstart(e){
// 手机按下 获取位置
let data=[Math.floor(e.changedTouches[0].pageX),Math.floor(e.changedTouches[0].pageY)];
this.array.New.push(data);
if(this.array.New.length==this.array.Dot){
this.get_similarity(this.array.New);
this.array.New=[];
}
},
touchEnd(e){
// 当手机每次抬起都会被清空
this.array.New=[];
},
// 计算相似度
get_similarity(array_new){
// 计算两点间距离
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
// 生成指定范围的二维点位
const randomPosInRange = (min, max) => Array.from({length: 2}, () => Math.floor(Math.random() * (max - min + 1)) + min);
// 计算各点的相互距离
const pointsDistance = (points) => {
let array = [];
for (let i = 0; i < points.length; i++) {
for (let j = i + 1; j < points.length; j++) {
const p1 = points[i];
const p2 = points[j];
array.push(distance(p1[0], p1[1], p2[0], p2[1]));
}
}
return array
};
// 计算数组中的最小值
const minInArray = (array) => array.sort((a, b) => a - b)[0];
// 计算各点距离与最小距离的倍数
const distanceMultiple = (points) => {
const distances = pointsDistance(points);
const minDistance = minInArray(distances);
const code = distances.map(distance => round(distance / minDistance, 5));
code.shift();
return code
};
// 四舍五入到指定位数
const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
// 差异相关性
const approximateMatchArray = (arr1, arr2) => {
let scope = 0;
arr1 = arr1.sort();
arr2 = arr2.sort();
const part = 100 / arr1.length;
for (let i = 0; i < arr1.length; i++) {
const reduce = Math.abs(arr1[i] - arr2[i]);
const partScope = part * (1 - reduce / 10);
scope = scope + partScope
}
let damping = 105;
if (scope < 90) damping = 125;
scope = scope * (scope / damping);
if (scope > 100) scope = 0;
return scope
};
// 直接获取相似度
const getSimilarity = (points) => {
const code = distanceMultiple(this.array.Old);
const ity = distanceMultiple(points)
const scope = approximateMatchArray(code, ity);
const data={
likeness:Math.floor(scope),
location:this.array.New
}
if(Math.floor(scope)>=90){
data.msg="seal:ok";
this.$emit('success',data);
}else{
data.msg="seal:no";
this.$emit('fail',data);
}
};
// 运行
getSimilarity(array_new)
}
}
}
接下来就是在页面里调用了
<template>
<view class="content">
<seal
@success="success"
@fail="fail"
:data="data"
/>
</view>
</template>
<script>
import seal from '@/components/seal/seal.vue';
export default{
components:{seal},
data(){
return{
data:[[126, 76], [78, 132], [60, 44]]
}
},
methods:{
success(data){
uni.showLoading({title:"匹配成功",mask:true});
setTimeout(()=>{
uni.hideLoading();
},3000)
console.log(data)
},
fail(data){
console.log(data)
}
}
}
</script>
<style lang="scss" scoped>
.content{
100vw;
height: 100vh;
background-color: pink;
}
</style>