123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- import { getSystemInfoSync } from '../helpers/hooks/useNativeAPI'
- import { toDataURL, getCanvasRef } from '../helpers/hooks/useCanvasAPI'
- /**
- * 获取范围内的随机数
- * @param {Number} min 最小值
- * @param {Number} max 最大值
- */
- const randomNum = (min, max) => {
- return Math.floor(Math.random() * (max - min) + min)
- }
- /**
- * 获取范围内的随机颜色值
- * @param {Number} min 最小值
- * @param {Number} max 最大值
- */
- const randomColor = (min, max) => {
- const _r = randomNum(min, max)
- const _g = randomNum(min, max)
- const _b = randomNum(min, max)
- return `rgb(${_r}, ${_g}, ${_b})`
- }
- /**
- * 创建 canvas 绘图上下文
- * @param {Object} ctx canvas 绘图上下文
- * @param {Object} props 配置项
- * @param {String} props.str 验证码范围
- * @param {Number} props.num 验证码长度,默认值 6
- * @param {Number} props.width 画布宽度,默认值 120
- * @param {Number} props.height 画布高度,默认值 40
- * @param {String} props.bgColor 画布背景色
- * @param {String} props.fontColor 画布字体颜色
- * @param {Boolean} props.hasPoint 是否显示干扰点,默认 true
- * @param {Boolean} props.hasLine 是否显示干扰线,默认 true
- */
- const render = (ctx, props = {}) => {
- const { str, num, width, height, bgColor, fontColor, hasPoint, hasLine } = props
- const ratio = getSystemInfoSync(['window']).pixelRatio
- let vcode = ''
- // 绘制矩形,并设置填充色
- ctx.textBaseline = 'bottom'
- ctx.fillStyle = bgColor ? bgColor : randomColor(180, 240)
- ctx.scale(ratio, ratio)
- ctx.fillRect(0, 0, width, height)
- // 绘制随机生成 n 位的验证码
- for (let i = 0; i < num; i++) {
- const x = (width - 10) / num * i + 10
- const y = randomNum(height / 2, height)
- const deg = randomNum(-45, 45)
- const txt = str[randomNum(0, str.length)]
- const fontSize = randomNum(16, 40)
- const halfHeight = parseInt(height / 2)
- vcode += txt
- ctx.fillStyle = fontColor ? fontColor : randomColor(10, 100)
- ctx.font = `normal normal normal ${fontSize > halfHeight ? halfHeight : fontSize}px sans-serif`
- ctx.translate(x, y)
- ctx.rotate(deg * Math.PI / 180)
- ctx.fillText(txt, 0, 0)
- ctx.rotate(-deg * Math.PI / 180)
- ctx.translate(-x, -y)
- }
- // 绘制干扰线
- if (!!hasLine) {
- for (let i = 0; i < num; i++) {
- ctx.strokeStyle = randomColor(90, 180)
- ctx.beginPath()
- ctx.moveTo(randomNum(0, width), randomNum(0, height))
- ctx.lineTo(randomNum(0, width), randomNum(0, height))
- ctx.stroke()
- }
- }
- // 绘制干扰点
- if (!!hasPoint) {
- for (let i = 0; i < num * 10; i++) {
- ctx.fillStyle = randomColor(0, 255)
- ctx.beginPath()
- ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI)
- ctx.fill()
- }
- }
- return vcode
- }
- Component({
- properties: {
- str: {
- type: String,
- value: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
- },
- num: {
- type: Number,
- value: 6,
- },
- width: {
- type: Number,
- value: 120,
- },
- height: {
- type: Number,
- value: 40,
- },
- bgColor: {
- type: String,
- value: '',
- },
- fontColor: {
- type: String,
- value: '',
- },
- hasPoint: {
- type: Boolean,
- value: true,
- },
- hasLine: {
- type: Boolean,
- value: true,
- },
- canvasId: {
- type: String,
- value: 'wux-vcode',
- },
- },
- methods: {
- /**
- * 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中
- */
- createCanvasContext(props) {
- const { width, height, canvasId } = props
- const setBase64Url = ({ value, base64Url }) => {
- this.triggerEvent('change', { value, base64Url })
- }
- const renderCanvas = () => getCanvasRef(canvasId, this).then((canvas) => {
- const ctx = canvas.getContext('2d')
- const ratio = getSystemInfoSync(['window']).pixelRatio
- const canvasWidth = width * ratio
- const canvasHeight = height * ratio
- canvas.width = canvasWidth
- canvas.height = canvasHeight
-
- const value = render(ctx, props)
- return toDataURL({ width, height }, canvas)
- .then((base64Url) => {
- ctx.restore()
- return { value, base64Url }
- })
- })
- let promise = Promise.resolve()
- promise = promise.then(() => {
- return renderCanvas()
- })
- promise = promise.then(({ value, base64Url }) => {
- setBase64Url({ value, base64Url })
- }, (err) => {
- this.triggerEvent('error', err)
- // console.error(err)
- })
- return promise
- },
- draw() {
- this.createCanvasContext(this.data)
- },
- },
- ready() {
- this.createCanvasContext(this.data)
- },
- })
|