568 lines
16 KiB
JavaScript
568 lines
16 KiB
JavaScript
import Fingerprint2 from 'fingerprintjs2';//获取浏览器唯一标识
|
||
const isEmail = (email) => {
|
||
// let reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,})$/
|
||
let reg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
|
||
let result = reg.test(email)
|
||
return result
|
||
}
|
||
|
||
const getUploadUrl = () => {
|
||
let url = process.env.VUE_APP_BASE_URL || ''
|
||
// let url = "http://18.167.251.121:10086"
|
||
return url
|
||
}
|
||
|
||
function base64ToFile(urlData,name) {
|
||
let arr = urlData.split(',');
|
||
let mime = arr[0].match(/:(.*?);/)[1];
|
||
let bstr = atob(arr[1]);
|
||
let n = bstr.length;
|
||
let u8arr = new Uint8Array(n);
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n);
|
||
}
|
||
return new File([u8arr], name, {
|
||
type: mime
|
||
});
|
||
}
|
||
|
||
function dataURLtoBlob(dataurl) {//吧data url转为blob对象
|
||
var arr = dataurl.split(',');
|
||
var mime = arr[0].match(/:(.*?);/)[1];
|
||
var bstr = atob(arr[1]);
|
||
var n = bstr.length;
|
||
var u8arr = new Uint8Array(n);
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n);
|
||
}
|
||
return new Blob([u8arr], { type: mime });
|
||
}
|
||
|
||
function blobToFile(blob, fileName) {//给blob文件设置名字和日期
|
||
blob.lastModifiedDate = new Date();
|
||
blob.name = fileName;
|
||
return blob;
|
||
}
|
||
//下载图片
|
||
function downloadIamge(imgsrc, name) { // 下载图片地址和图片名
|
||
var image = new Image()
|
||
// 解决跨域 Canvas 污染问题
|
||
image.setAttribute('crossOrigin', 'anonymous')
|
||
image.onload = function () {
|
||
var canvas = document.createElement('canvas')
|
||
canvas.width = image.width
|
||
canvas.height = image.height
|
||
var context = canvas.getContext('2d')
|
||
context.drawImage(image, 0, 0, image.width, image.height)
|
||
var url = canvas.toDataURL('image/jpeg') // 得到图片的base64编码数据
|
||
var a = document.createElement('a') // 生成一个a元素
|
||
var event = new MouseEvent('click') // 创建一个单击事件
|
||
a.download = name || 'generate' // 设置图片名称
|
||
a.href = url // 将生成的URL设置为a.href属性
|
||
a.target = '_blank'
|
||
a.dispatchEvent(event) // 触发a的单击事件
|
||
image.remove()
|
||
}
|
||
image.src = imgsrc
|
||
}
|
||
|
||
function dataURLtoFile(dataurl, filename) {//吧url转为文件对象,指定文件名称
|
||
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
||
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n);
|
||
}
|
||
var blob = dataURLtoBlob(dataurl);
|
||
return blobToFile(blob, filename);
|
||
}
|
||
|
||
const base64toFile = (dataurl, filename = 'file') => {//转换base64
|
||
let arr = dataurl.split(',')
|
||
let mime = arr[0].match(/:(.*?);/)[1]
|
||
let suffix = mime.split('/')[1]
|
||
let bstr = atob(arr[1])
|
||
let n = bstr.length
|
||
let u8arr = new Uint8Array(n)
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n)
|
||
}
|
||
return new File([u8arr], `${filename}.${suffix}`, {
|
||
type: mime
|
||
})
|
||
|
||
}
|
||
|
||
function rgbToHsv([R, G, B]) {//根据rgb获取hsv
|
||
R /= 255
|
||
G /= 255
|
||
B /= 255
|
||
const max = Math.max(R, G, B)
|
||
const min = Math.min(R, G, B)
|
||
const delta = max - min
|
||
var H, S, V
|
||
if (delta === 0) {
|
||
H = 0;
|
||
} else if (max === R) {
|
||
H = ((G - B) / delta) % 6;
|
||
} else if (max === G) {
|
||
H = (B - R) / delta + 2;
|
||
} else { // max === B
|
||
H = (R - G) / delta + 4;
|
||
}
|
||
H = Math.round(H * 60); // 范围为 0-360
|
||
if (H < 0) {
|
||
H = 360 + H
|
||
}
|
||
if (max === 0) {
|
||
S = 0;
|
||
} else {
|
||
S = delta / max;
|
||
}
|
||
S = Math.round(S * 100); // 范围为 0-100
|
||
V = Math.round(max * 100); // 范围为 0-100
|
||
return [H, S, V]
|
||
}
|
||
|
||
const formatTime = (timestamp, fmt) => {//吧时间戳转为YYYY-MM-DD hh:mm:ss格式
|
||
// date = new Date(), fmt = 'MM/dd/yyyy';
|
||
let date = new Date();
|
||
date.setTime(timestamp * 1000);
|
||
|
||
if (!fmt) {
|
||
formatRule ? (fmt = formatRule) : (fmt = "YYYY-MM-DD hh:mm:ss");
|
||
}
|
||
// console.log(formatRule)
|
||
let o = {
|
||
'M+': date.getMonth() + 1, // 月份
|
||
'D+': date.getDate(), // 日
|
||
'h+': date.getHours(), // 小时
|
||
'm+': date.getMinutes(), // 分
|
||
's+': date.getSeconds(), // 秒
|
||
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
|
||
'S+': date.getMilliseconds(), // 毫秒
|
||
'a': date.getHours() > 12
|
||
? 'PM'
|
||
: 'AM' // 上午还是下午
|
||
};
|
||
if (/(Y+)/.test(fmt)) {
|
||
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||
}
|
||
if (/(a)/.test(fmt) && o['h+'] > 12) {
|
||
o['h+'] = o['h+'] - 12
|
||
}
|
||
for (let k in o) {
|
||
if (new RegExp('(' + k + ')').test(fmt)) {
|
||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1)
|
||
? (o[k])
|
||
: (('00' + o[k]).substr(('' + o[k]).length)));
|
||
}
|
||
}
|
||
|
||
return fmt;
|
||
}
|
||
|
||
const isMoible = () => {//判断是否是移动端
|
||
let is_mobile = navigator.userAgent.toLowerCase().match(/(ipad|ipod|iphone|android|coolpad|mmp|smartphone|midp|wap|xoom|symbian|j2me|blackberry|wince)/i) != null;
|
||
// alert(navigator.userAgent.toLowerCase())
|
||
var isiPad = (navigator.maxTouchPoints && navigator.maxTouchPoints > 1);
|
||
// if (is_mobile) {
|
||
// return true//判断是否在正则内
|
||
// } else if(window.matchMedia("(pointer:fine)").matches){
|
||
// return false//判断是否支持鼠标
|
||
// }else{
|
||
// isiPad//判断触摸点
|
||
// }
|
||
if (is_mobile) {
|
||
return true//判断是否在正则内
|
||
} else{
|
||
return isiPad//判断触摸点
|
||
}
|
||
}
|
||
|
||
let setPubDate = (date)=>{
|
||
const timestamp = new Date(date);
|
||
const now = new Date();
|
||
// 计算时间差(以毫秒为单位)
|
||
const differenceMs = now - timestamp;
|
||
const seconds = Math.floor(differenceMs / 1000);
|
||
const minutes = Math.floor(seconds / 60);
|
||
const hours = Math.floor(minutes / 60);
|
||
const days = Math.floor(hours / 24);
|
||
const weeks = Math.floor(days / 7);
|
||
const months = Math.floor(days / 30);
|
||
const years = Math.floor(days / 365);
|
||
|
||
// 根据时间差的大小返回不同的描述
|
||
if (years > 0) {
|
||
return `${years} years ago`;
|
||
} else if (months > 0) {
|
||
return `${months} months ago`;
|
||
} else if (weeks > 0) {
|
||
return `${weeks} Weeks ago`;
|
||
} else if (days > 0) {
|
||
return `1 days ago`;
|
||
} else if (hours > 0) {
|
||
return `${hours} Hours ago`;
|
||
} else if (minutes > 0) {
|
||
return `${minutes} minutes ago`;
|
||
} else {
|
||
return `1 minute ago`;
|
||
}
|
||
}
|
||
|
||
function getBrowserInfo() {//获取是什么浏览器
|
||
var agent = navigator.userAgent.toLowerCase();
|
||
var userAgent = navigator.userAgent;
|
||
var regStr_ie = /msie [\d.]+;/gi;
|
||
var regStr_ff = /firefox\/[\d.]+/gi
|
||
var regStr_chrome = /chrome\/[\d.]+/gi;
|
||
var regStr_saf = /safari\/[\d.]+/gi;
|
||
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
|
||
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
|
||
//IE
|
||
if (agent.indexOf("msie") > 0) {
|
||
return agent.match(regStr_ie);
|
||
}
|
||
//firefox
|
||
if (agent.indexOf("firefox") > 0) {
|
||
return agent.match(regStr_ff);
|
||
}
|
||
//Chrome
|
||
if (agent.indexOf("chrome") > 0) {
|
||
return agent.match(regStr_chrome);
|
||
}
|
||
//Safari
|
||
if (agent.indexOf("safari") > 0 && agent.indexOf("chrome") < 0) {
|
||
return agent.match(regStr_saf);
|
||
}
|
||
}
|
||
async function murmur(){//生成唯一标识 ,暂时没有使用
|
||
return await new Promise((resolve,reject)=>{
|
||
Fingerprint2.get(function (components) {
|
||
const values = components.map(function (
|
||
component,
|
||
index
|
||
) {
|
||
if (index === 0) {
|
||
//把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
|
||
return component.value.replace(/\bNetType\/\w+\b/, "");
|
||
}
|
||
return component.value;
|
||
});
|
||
// 生成最终id murmur
|
||
let murmur = Fingerprint2.x64hash128(values.join(""), 31);
|
||
resolve(murmur)
|
||
});
|
||
})
|
||
}
|
||
/**
|
||
* @description: 计算canvas渐变起始坐标
|
||
* @param {number} canvas width
|
||
* @param {number} canvas height
|
||
* @param {number} angle 角度
|
||
* @return {*}
|
||
*/
|
||
function calculateGradientCoordinate(width,height,angle) {
|
||
if (angle >= 360) angle = angle - 360;
|
||
if (angle < 0) angle = angle + 360;
|
||
angle = Math.round(angle);
|
||
|
||
// 当渐变轴垂直于矩形水平边上的两种结果
|
||
if (angle === 0) {
|
||
return {
|
||
x0: Math.round(width / 2),
|
||
y0: height,
|
||
x1: Math.round(width / 2),
|
||
y1: 0,
|
||
};
|
||
}
|
||
if (angle === 180) {
|
||
return {
|
||
x0: Math.round(width / 2),
|
||
y0: 0,
|
||
x1: Math.round(width / 2),
|
||
y1: height,
|
||
};
|
||
}
|
||
|
||
// 当渐变轴垂直于矩形垂直边上的两种结果
|
||
if (angle === 90) {
|
||
return {
|
||
x0: 0,
|
||
y0: Math.round(height / 2),
|
||
x1: width,
|
||
y1: Math.round(height / 2),
|
||
};
|
||
}
|
||
if (angle === 270) {
|
||
return {
|
||
x0: width,
|
||
y0: Math.round(height / 2),
|
||
x1: 0,
|
||
y1: Math.round(height / 2),
|
||
};
|
||
}
|
||
|
||
// 从矩形左下角至右上角的对角线的角度
|
||
const alpha = Math.round(
|
||
(Math.asin(width / Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))) *
|
||
180) /
|
||
Math.PI,
|
||
);
|
||
|
||
// 当渐变轴分别于矩形的两条对角线重合情况下的四种结果
|
||
if (angle === alpha) {
|
||
return {
|
||
x0: 0,
|
||
y0: height,
|
||
x1: width,
|
||
y1: 0,
|
||
};
|
||
}
|
||
if (angle === 180 - alpha) {
|
||
return {
|
||
x0: 0,
|
||
y0: 0,
|
||
x1: width,
|
||
y1: height,
|
||
};
|
||
}
|
||
if (angle === 180 + alpha) {
|
||
return {
|
||
x0: width,
|
||
y0: 0,
|
||
x1: 0,
|
||
y1: height,
|
||
};
|
||
}
|
||
if (angle === 360 - alpha) {
|
||
return {
|
||
x0: width,
|
||
y0: height,
|
||
x1: 0,
|
||
y1: 0,
|
||
};
|
||
}
|
||
|
||
// 以矩形的中点为坐标原点,向上为Y轴正方向,向右为X轴正方向建立直角坐标系
|
||
let x0 = 0,
|
||
y0 = 0,
|
||
x1 = 0,
|
||
y1 = 0;
|
||
|
||
// 当渐变轴与矩形的交点落在水平线上
|
||
if (
|
||
angle < alpha || // 处于第一象限
|
||
(angle > 180 - alpha && angle < 180) || // 处于第二象限
|
||
(angle > 180 && angle < 180 + alpha) || // 处于第三象限
|
||
angle > 360 - alpha // 处于第四象限
|
||
) {
|
||
// 将角度乘以(PI/180)即可转换为弧度
|
||
const radian = (angle * Math.PI) / 180;
|
||
// 当在第一或第四象限,y是height / 2,否则y是-height / 2
|
||
const y = angle < alpha || angle > 360 - alpha ? height / 2 : -height / 2;
|
||
const x = Math.tan(radian) * y;
|
||
// 当在第一或第二象限,l是width / 2 - x,否则l是-width / 2 - x
|
||
const l =
|
||
angle < alpha || (angle > 180 - alpha && angle < 180)
|
||
? width / 2 - x
|
||
: -width / 2 - x;
|
||
const n = Math.pow(Math.sin(radian), 2) * l;
|
||
x1 = x + n;
|
||
y1 = y + n / Math.tan(radian);
|
||
x0 = -x1;
|
||
y0 = -y1;
|
||
}
|
||
|
||
// 当渐变轴与矩形的交点落在垂直线上
|
||
if (
|
||
(angle > alpha && angle < 90) || // 处于第一象限
|
||
(angle > 90 && angle < 180 - alpha) || // 处于第二象限
|
||
(angle > 180 + alpha && angle < 270) || // 处于第三象限
|
||
(angle > 270 && angle < 360 - alpha) // 处于第四象限
|
||
) {
|
||
// 将角度乘以(PI/180)即可转换为弧度
|
||
const radian = ((90 - angle) * Math.PI) / 180;
|
||
// 当在第一或第二象限,x是width / 2,否则x是-width / 2
|
||
const x =
|
||
(angle > alpha && angle < 90) || (angle > 90 && angle < 180 - alpha)
|
||
? width / 2
|
||
: -width / 2;
|
||
const y = Math.tan(radian) * x;
|
||
// 当在第一或第四象限,l是height / 2 - y,否则l是-height / 2 - y
|
||
const l =
|
||
(angle > alpha && angle < 90) || (angle > 270 && angle < 360 - alpha)
|
||
? height / 2 - y
|
||
: -height / 2 - y;
|
||
const n = Math.pow(Math.sin(radian), 2) * l;
|
||
x1 = x + n / Math.tan(radian);
|
||
y1 = y + n;
|
||
x0 = -x1;
|
||
y0 = -y1;
|
||
}
|
||
|
||
// 坐标系更改为canvas标准,Y轴向下为正方向
|
||
x0 = Math.round(x0 + width / 2);
|
||
y0 = Math.round(height / 2 - y0);
|
||
x1 = Math.round(x1 + width / 2);
|
||
y1 = Math.round(height / 2 - y1);
|
||
return {x0, y0, x1, y1};
|
||
}
|
||
|
||
const setGradual = (colorObj,colorWidth,colorHeight)=>{
|
||
let width = colorWidth || 320
|
||
let height = colorHeight || 700
|
||
const canvas = document.createElement("canvas");
|
||
const ctx = canvas.getContext("2d");
|
||
canvas.width = width;
|
||
canvas.height = height;
|
||
let {x0, y0, x1, y1} = calculateGradientCoordinate(width,height,colorObj.angle)
|
||
const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
|
||
colorObj.gradientList.forEach(item => {
|
||
let left = item.left.split('%')[0]/100
|
||
let rgba = `rgba(${item.rgba.r},${item.rgba.g},${item.rgba.b},${item.rgba.a})`
|
||
gradient.addColorStop(left, rgba); // 起始颜色
|
||
});
|
||
ctx.fillStyle = gradient;
|
||
ctx.fillRect(0, 0, width, height);
|
||
const dataURL = canvas.toDataURL('image/jpg');
|
||
return dataURL
|
||
}
|
||
function segmentImage(markerImage,fullImage,size){
|
||
return new Promise((resolve, reject) => {
|
||
const markerCanvas = document.createElement('canvas');
|
||
const fullCanvas = document.createElement('canvas');
|
||
const nullCanvas = document.createElement('canvas');
|
||
const ctx1 = markerCanvas.getContext('2d');
|
||
const ctx2 = fullCanvas.getContext('2d');
|
||
const ctx3 = nullCanvas.getContext('2d');
|
||
markerCanvas.width=size.width
|
||
markerCanvas.height=size.height
|
||
fullCanvas.height=size.height
|
||
fullCanvas.width=size.width
|
||
nullCanvas.height=size.height
|
||
nullCanvas.width=size.width
|
||
let targetFrontUrl = ''
|
||
let targetBackUrl = ''
|
||
const marker = new Image();
|
||
const full = new Image();
|
||
marker.crossOrigin = 'anonymous';
|
||
full.crossOrigin = 'anonymous';
|
||
marker.onload = () => {
|
||
ctx1.drawImage(marker,0,0 ,size.width, size.height);
|
||
full.onload = () => {
|
||
ctx2.drawImage(full,0,0, size.width, size.height);
|
||
segmentImageItem();
|
||
};
|
||
full.src = fullImage;
|
||
};
|
||
marker.src = markerImage;
|
||
function segmentImageItem() {
|
||
|
||
const markerData = ctx1.getImageData(0, 0, size.width, size.height);
|
||
const fullData = ctx2.getImageData(0, 0, size.width, size.height);
|
||
|
||
const color1 = { r: 255, g: 0, b: 0 }; // 第一个颜色
|
||
const color2 = { r: 0, g: 255, b: 0 }; // 第二个颜色
|
||
|
||
const threshold = 100; // 颜色匹配的容差
|
||
// const isColorMatch = (r, g, b, color) =>
|
||
// (Math.abs(r - color.r) < threshold) || (Math.abs(0 - color.r) < threshold) &&
|
||
// (Math.abs(g - color.g) < threshold) || (Math.abs(0 - color.g) < threshold) &&
|
||
// (Math.abs(b - color.b) < threshold) || (Math.abs(0 - color.b) < threshold)
|
||
|
||
const isColorMatch = (r, g, b, color) =>
|
||
((color.r >= color.g) && r >= g) ||
|
||
((color.r < color.g) && r < g)
|
||
|
||
// (Math.abs(b - color.b) < threshold || Math.abs(0 - color.b) < threshold)
|
||
|
||
const output1 = ctx3.createImageData(size.width, size.height);
|
||
const output2 = ctx3.createImageData(size.width, size.height);
|
||
for (let i = 0; i < markerData.data.length; i += 4) {
|
||
const r = markerData.data[i];
|
||
const g = markerData.data[i + 1];
|
||
const b = markerData.data[i + 2];
|
||
let a = markerData.data[i + 3];
|
||
a>1?a = 255:0
|
||
if (r>=g && a>1) {
|
||
// 将完整图像中对应的像素复制到第一个输出图像
|
||
output1.data[i] = fullData.data[i];
|
||
output1.data[i + 1] = fullData.data[i + 1];
|
||
output1.data[i + 2] = fullData.data[i + 2];
|
||
output1.data[i + 3] = fullData.data[i + 3];
|
||
// output1.data[i] = 158;
|
||
// output1.data[i + 1] = 51;
|
||
// output1.data[i + 2] = 0;
|
||
// output1.data[i + 3] = 255;
|
||
// 第二个图像的像素置为透明
|
||
output2.data[i] = 0;
|
||
output2.data[i + 1] = 0;
|
||
output2.data[i + 2] = 0;
|
||
output2.data[i + 3] = 0;
|
||
} else if (r<g && a>1) {
|
||
// 将完整图像中对应的像素复制到第二个输出图像
|
||
output2.data[i] = fullData.data[i];
|
||
output2.data[i + 1] = fullData.data[i + 1];
|
||
output2.data[i + 2] = fullData.data[i + 2];
|
||
output2.data[i + 3] = fullData.data[i + 3];
|
||
// output2.data[i] = 158;
|
||
// output2.data[i + 1] = 51;
|
||
// output2.data[i + 2] = 0;
|
||
// output2.data[i + 3] = 255;
|
||
// 第一个图像的像素置为透明
|
||
output1.data[i] = 0;
|
||
output1.data[i + 1] = 0;
|
||
output1.data[i + 2] = 0;
|
||
output1.data[i + 3] = 0;
|
||
} else {
|
||
// 两个图像的像素都置为透明
|
||
output1.data[i] = 0;
|
||
output1.data[i + 1] = 0;
|
||
output1.data[i + 2] = 0;
|
||
output1.data[i + 3] = 0;
|
||
|
||
output2.data[i] = 0;
|
||
output2.data[i + 1] = 0;
|
||
output2.data[i + 2] = 0;
|
||
output2.data[i + 3] = 0;
|
||
}
|
||
}
|
||
const createImageURL = (imageData) => {
|
||
const canvas = document.createElement('canvas');
|
||
canvas.width = size.width;
|
||
canvas.height = size.height;
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.putImageData(imageData, 0, 0);
|
||
let data = canvas.toDataURL('image/png')
|
||
canvas.remove()
|
||
return data;
|
||
};
|
||
targetBackUrl =createImageURL(output2)
|
||
targetFrontUrl =createImageURL(output1)
|
||
resolve({targetFrontUrl, targetBackUrl})
|
||
markerCanvas.remove()
|
||
fullCanvas.remove()
|
||
nullCanvas.remove()
|
||
}
|
||
})
|
||
}
|
||
export {
|
||
isEmail,
|
||
getUploadUrl,
|
||
base64ToFile,
|
||
dataURLtoFile,
|
||
blobToFile,
|
||
base64toFile,
|
||
rgbToHsv,
|
||
formatTime,
|
||
dataURLtoBlob,
|
||
isMoible,
|
||
downloadIamge,
|
||
getBrowserInfo,
|
||
setPubDate,
|
||
murmur,
|
||
setGradual,
|
||
calculateGradientCoordinate,
|
||
segmentImage,
|
||
} |