go-captcha-angular
Version:
GoCaptcha for Angular, which implements click mode, slider mode, drag-drop mode and rotation mode.
1 lines • 102 kB
Source Map (JSON)
{"version":3,"file":"go-captcha-angular.mjs","sources":["../../../projects/go-captcha-angular/src/lib/modules/button/button-instance.ts","../../../projects/go-captcha-angular/src/lib/icons/btn-default-icon.component.ts","../../../projects/go-captcha-angular/src/lib/icons/btn-error-icon.component.ts","../../../projects/go-captcha-angular/src/lib/icons/btn-warn-icon.component.ts","../../../projects/go-captcha-angular/src/lib/icons/btn-success-icon.component.ts","../../../projects/go-captcha-angular/src/lib/modules/button/button.component.ts","../../../projects/go-captcha-angular/src/lib/modules/button/button.component.html","../../../projects/go-captcha-angular/src/lib/modules/click/click-instance.ts","../../../projects/go-captcha-angular/src/lib/helper/helper.ts","../../../projects/go-captcha-angular/src/lib/icons/close-icon.component.ts","../../../projects/go-captcha-angular/src/lib/icons/refresh-icon.component.ts","../../../projects/go-captcha-angular/src/lib/icons/loading-icon.component.ts","../../../projects/go-captcha-angular/src/lib/modules/click/click.component.ts","../../../projects/go-captcha-angular/src/lib/modules/click/click.component.html","../../../projects/go-captcha-angular/src/lib/modules/slide/slide-instance.ts","../../../projects/go-captcha-angular/src/lib/icons/arrows-icon.component.ts","../../../projects/go-captcha-angular/src/lib/modules/slide/slide.component.ts","../../../projects/go-captcha-angular/src/lib/modules/slide/slide.component.html","../../../projects/go-captcha-angular/src/lib/modules/slide-region/slide-region-instance.ts","../../../projects/go-captcha-angular/src/lib/modules/slide-region/slide-region.component.ts","../../../projects/go-captcha-angular/src/lib/modules/slide-region/slide-region.component.html","../../../projects/go-captcha-angular/src/lib/modules/rotate/rotate-instance.ts","../../../projects/go-captcha-angular/src/lib/modules/rotate/rotate.component.ts","../../../projects/go-captcha-angular/src/lib/modules/rotate/rotate.component.html","../../../projects/go-captcha-angular/src/lib/go-captcha.module.ts","../../../projects/go-captcha-angular/src/public-api.ts","../../../projects/go-captcha-angular/src/go-captcha-angular.ts"],"sourcesContent":["export interface ButtonConfig {\n width?: number;\n height?: number;\n verticalPadding?: number;\n horizontalPadding?: number;\n}\n\nexport const defaultButtonConfig = ():ButtonConfig => ({\n width: 330,\n height: 44,\n verticalPadding: 12,\n horizontalPadding: 16,\n})\n\nexport type ButtonType = \"default\" | \"warn\" | \"error\" | \"success\";\n\nexport interface ButtonInstance {\n config?: ButtonConfig;\n clickEvent?: () => void;\n disabled?: boolean;\n type?: ButtonType;\n title?: string;\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'btn-default-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <circle fill=\"#3E7CFF\" cx=\"100\" cy=\"100\" r=\"96.3\"/>\n <path fill=\"#FFFFFF\" d=\"M140.8,64.4l-39.6-11.9h-2.4L59.2,64.4c-1.6,0.8-2.8,2.4-2.8,4v24.1c0,25.3,15.8,45.9,42.3,54.6\n\\tc0.4,0,0.8,0.4,1.2,0.4c0.4,0,0.8,0,1.2-0.4c26.5-8.7,42.3-28.9,42.3-54.6V68.3C143.5,66.8,142.3,65.2,140.8,64.4z\"/>\n </svg>`,\n})\nexport class BtnDefaultIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'btn-error-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path fill=\"#ED4630\" d=\"M184,26.6L102.4,2.1h-4.9L16,26.6c-3.3,1.6-5.7,4.9-5.7,8.2v49.8c0,52.2,32.6,94.7,87.3,112.6\n\\tc0.8,0,1.6,0.8,2.4,0.8s1.6,0,2.4-0.8c54.7-18,87.3-59.6,87.3-112.6V34.7C189.8,31.5,187.3,28.2,184,26.6z M134.5,123.1\n\\tc3.1,3.1,3.1,8.2,0,11.3c-1.6,1.6-3.6,2.3-5.7,2.3s-4.1-0.8-5.7-2.3L100,111.3l-23.1,23.1c-1.6,1.6-3.6,2.3-5.7,2.3\n\\tc-2,0-4.1-0.8-5.7-2.3c-3.1-3.1-3.1-8.2,0-11.3L88.7,100L65.5,76.9c-3.1-3.1-3.1-8.2,0-11.3c3.1-3.1,8.2-3.1,11.3,0L100,88.7\n\\tl23.1-23.1c3.1-3.1,8.2-3.1,11.3,0c3.1,3.1,3.1,8.2,0,11.3L111.3,100L134.5,123.1z\"/>\n </svg>`,\n})\nexport class BtnErrorIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'btn-warn-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path fill=\"#FFA000\" d=\"M184,26.6L102.4,2.1h-4.9L16,26.6c-3.3,1.6-5.7,4.9-5.7,8.2v49.8c0,52.2,32.6,94.7,87.3,112.6\n\\tc0.8,0,1.6,0.8,2.4,0.8s1.6,0,2.4-0.8c54.7-18,87.3-59.6,87.3-112.6V34.7C189.8,31.5,187.3,28.2,184,26.6z M107.3,109.1\n\\tc-0.5,5.4-3.9,7.9-7.3,7.9c-2.5,0,0,0,0,0c-3.2-0.6-5.7-2-6.8-7.4l-4.4-50.9c0-5.1,6.2-9.7,11.5-9.7c5.3,0,11,4.7,11,9.9\n\\tL107.3,109.1z M109.3,133.3c0,5.1-4.2,9.3-9.3,9.3c-5.1,0-9.3-4.2-9.3-9.3c0-5.1,4.2-9.3,9.3-9.3C105.1,124,109.3,128.1,109.3,133.3\n\\tz\"/>\n </svg>`,\n})\nexport class BtnWarnIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'btn-success-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path fill=\"#5EAA2F\" d=\"M183.3,27.2L102.4,2.9h-4.9L16.7,27.2C13.4,28.8,11,32,11,35.3v49.4c0,51.8,32.4,93.9,86.6,111.7\n\\tc0.8,0,1.6,0.8,2.4,0.8c0.8,0,1.6,0,2.4-0.8c54.2-17.8,86.6-59.1,86.6-111.7V35.3C189,32,186.6,28.8,183.3,27.2z M146.1,81.4\n\\tl-48.5,48.5c-1.6,1.6-3.2,2.4-5.7,2.4c-2.4,0-4-0.8-5.7-2.4L62,105.7c-3.2-3.2-3.2-8.1,0-11.3c3.2-3.2,8.1-3.2,11.3,0l18.6,18.6\n\\tl42.9-42.9c3.2-3.2,8.1-3.2,11.3,0C149.4,73.3,149.4,78.2,146.1,81.4L146.1,81.4z\"/>\n </svg>`,\n})\nexport class BtnSuccessIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input, OnInit} from '@angular/core';\nimport {ButtonType, ButtonConfig, defaultButtonConfig} from \"./button-instance\";\n\n@Component({\n selector: 'go-captcha-button',\n templateUrl: './button.component.html',\n styleUrls: ['./button.component.scss'],\n})\nexport class ButtonComponent implements OnInit {\n @Input()\n config?: ButtonConfig = defaultButtonConfig()\n @Input()\n clickEvent?: (e: Event) => void;\n @Input()\n disabled?: boolean = false\n @Input()\n type?: ButtonType = \"default\"\n @Input()\n title?: string = \"点击按键进行验证\"\n\n ngOnInit() {\n this.config = {...defaultButtonConfig(), ...this.config}\n }\n\n handleClick(e) {\n this.clickEvent && this.clickEvent(e)\n }\n}\n","<div\n [class]=\"['go-captcha', 'gc-button-mode', 'gc-btn-block', 'gc-'+type, disabled ? 'gc-disabled' : '' ]\"\n (click)=\"handleClick($event)\"\n [style]=\"{\n 'width': config.width + 'px',\n 'height': config.height + 'px',\n 'padding-left': config.horizontalPadding + 'px',\n 'padding-right': config.horizontalPadding + 'px',\n 'padding-top': config.verticalPadding + 'px',\n 'padding-bottom': config.verticalPadding + 'px',\n }\"\n>\n <div [class]=\"{'gc-ripple': type === 'default'}\" [ngSwitch]=\"type\">\n <btn-default-icon *ngSwitchCase=\"'default'\"></btn-default-icon>\n <btn-warn-icon *ngSwitchCase=\"'warn'\"></btn-warn-icon>\n <btn-error-icon *ngSwitchCase=\"'error'\"></btn-error-icon>\n <btn-success-icon *ngSwitchCase=\"'success'\"></btn-success-icon>\n </div>\n <span>{{title}}</span>\n</div>","\nexport interface ClickRef {\n reset: () => void,\n clear: () => void,\n refresh: () => void,\n close: () => void,\n}\n\nexport interface ClickConfig {\n width?: number;\n height?: number;\n thumbWidth?: number;\n thumbHeight?: number;\n verticalPadding?: number;\n horizontalPadding?: number;\n showTheme?: boolean;\n title?: string;\n buttonText?: string;\n iconSize?: number;\n dotSize?: number;\n}\n\nexport const defaultClickConfig = ():ClickConfig => ({\n width: 300,\n height: 220,\n thumbWidth: 150,\n thumbHeight: 40,\n verticalPadding: 16,\n horizontalPadding: 12,\n showTheme: true,\n title: \"请在下图依次点击\",\n buttonText: \"确认\",\n iconSize: 22,\n dotSize: 24,\n})\n\nexport interface ClickData {\n image: string;\n thumb: string;\n}\n\nexport const defaultData = (): ClickData => ({\n image: \"\", thumb: \"\"\n})\n\nexport interface ClickDot {\n key: number,\n index: number,\n x: number,\n y: number,\n}\n\nexport interface ClickEvent {\n click?: (x: number, y: number) => void;\n callback?: () => void;\n refresh?: () => void;\n close?: () => void;\n confirm?:(dots: Array<ClickDot>, clear:(fn: Function) => void) => void;\n}\n\nexport interface ClickInstance {\n data: ClickData,\n config?: ClickConfig;\n events?: ClickEvent,\n}\n","/**\n * @Author Awen\n * @Date 2024/05/25\n * @Email wengaolng@gmail.com\n **/\n\nexport function getDomXY(dom: any){\n let x = 0\n let y = 0\n if (dom.getBoundingClientRect) {\n const box = dom.getBoundingClientRect();\n const D = document.documentElement;\n x = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft;\n y = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop\n }\n else{\n while (dom !== document.body) {\n x += dom.offsetLeft\n y += dom.offsetTop\n dom = dom.offsetParent\n }\n }\n return {\n domX: x,\n domY: y\n }\n}\n\nexport function checkTargetFather(that: any, e: any) {\n let parent = e.relatedTarget\n try{\n while(parent && parent !== that) {\n parent = parent.parentNode\n }\n }catch (e){\n console.warn(e)\n }\n\n return parent !== that\n}\n\nexport function mergeToOver(src: any, dest: any) {\n for (const ccKey in src) {\n if (dest.hasOwnProperty(ccKey)) {\n dest[ccKey] = src[ccKey]\n }\n }\n}\n\n\nexport function mergeTo(src: any, dest: any) {\n for (const ccKey in src) {\n if (!dest.hasOwnProperty(ccKey)) {\n dest[ccKey] = src[ccKey]\n }\n }\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'close-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path d=\"M100.1,189.9C100.1,189.9,100,189.9,100.1,189.9c-49.7,0-90-40.4-90-89.9c0-49.6,40.4-89.9,89.9-89.9\n\\t\\tc49.6,0,89.9,40.4,89.9,89.9c0,18.2-5.4,35.7-15.6,50.7c-1.5,2.1-3.6,3.4-6.1,3.9c-2.5,0.4-5-0.1-7-1.6c-4.2-3-5.3-8.6-2.4-12.9\n\\t\\tc8.1-11.9,12.4-25.7,12.4-40.1c0-39.2-31.9-71.1-71.1-71.1c-39.2,0-71.1,31.9-71.1,71.1c0,39.2,31.9,71.1,71.1,71.1\n\\t\\tc7.7,0,15.3-1.2,22.6-3.6c2.4-0.8,4.9-0.6,7.2,0.5c2.2,1.1,3.9,3.1,4.7,5.5c1.6,4.9-1,10.2-5.9,11.9\n\\t\\tC119.3,188.4,109.8,189.9,100.1,189.9z M73,136.4C73,136.4,73,136.4,73,136.4c-2.5,0-4.9-1-6.7-2.8c-3.7-3.7-3.7-9.6,0-13.3\n\\t\\tL86.7,100L66.4,79.7c-3.7-3.7-3.7-9.6,0-13.3c3.7-3.7,9.6-3.7,13.3,0L100,86.7l20.3-20.3c1.8-1.8,4.1-2.8,6.7-2.8c0,0,0,0,0,0\n\\t\\tc2.5,0,4.9,1,6.7,2.8c1.8,1.8,2.8,4.1,2.8,6.7c0,2.5-1,4.9-2.8,6.7L113.3,100l20.3,20.3c3.7,3.7,3.7,9.6,0,13.3\n\\t\\tc-3.7,3.7-9.6,3.7-13.3,0L100,113.3l-20.3,20.3C77.9,135.4,75.5,136.4,73,136.4z\"/>\n </svg>`,\n})\nexport class CloseIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'refresh-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path d=\"M135,149.9c-10.7,7.6-23.2,11.4-36,11.2c-1.7,0-3.4-0.1-5-0.3c-0.7-0.1-1.4-0.2-2-0.3c-1.3-0.2-2.6-0.4-3.9-0.6\n\\tc-0.8-0.2-1.6-0.4-2.3-0.5c-1.2-0.3-2.5-0.6-3.7-1c-0.6-0.2-1.2-0.4-1.7-0.6c-1.4-0.5-2.8-1-4.2-1.5c-0.3-0.1-0.6-0.3-0.9-0.4\n\\tc-1.6-0.7-3.2-1.4-4.7-2.3c-0.1,0-0.1-0.1-0.2-0.1c-5.1-2.9-9.8-6.4-14-10.6c-0.1-0.1-0.1-0.1-0.2-0.2c-1.3-1.3-2.5-2.7-3.7-4.1\n\\tc-0.2-0.3-0.5-0.6-0.7-0.9c-8.4-10.6-13.5-24.1-13.5-38.8h14.3c0.4,0,0.7-0.2,0.9-0.5c0.2-0.3,0.2-0.8,0-1.1L29.5,60.9\n\\tc-0.2-0.3-0.5-0.5-0.9-0.5c-0.4,0-0.7,0.2-0.9,0.5L3.8,97.3c-0.2,0.3-0.2,0.7,0,1.1c0.2,0.3,0.5,0.5,0.9,0.5h14.3\n\\tc0,17.2,5.3,33.2,14.3,46.4c0.1,0.2,0.2,0.4,0.3,0.6c0.9,1.4,2,2.6,3,3.9c0.4,0.5,0.7,1,1.1,1.5c1.5,1.8,3,3.5,4.6,5.2\n\\tc0.2,0.2,0.3,0.3,0.5,0.5c5.4,5.5,11.5,10.1,18.2,13.8c0.2,0.1,0.3,0.2,0.5,0.3c1.9,1,3.9,2,5.9,2.9c0.5,0.2,1,0.5,1.5,0.7\n\\tc1.7,0.7,3.5,1.3,5.2,1.9c0.8,0.3,1.7,0.6,2.5,0.8c1.5,0.5,3.1,0.8,4.7,1.2c1.1,0.2,2.1,0.5,3.2,0.7c0.4,0.1,0.9,0.2,1.3,0.3\n\\tc1.5,0.3,3,0.4,4.5,0.6c0.5,0.1,1.1,0.2,1.6,0.2c2.7,0.3,5.4,0.4,8.1,0.4c16.4,0,32.5-5.1,46.2-14.8c4.4-3.1,5.5-9.2,2.4-13.7\n\\tC145.5,147.8,139.4,146.7,135,149.9 M180.6,98.9c0-17.2-5.3-33.1-14.2-46.3c-0.1-0.2-0.2-0.5-0.4-0.7c-1.1-1.6-2.3-3.1-3.5-4.6\n\\tc-0.1-0.2-0.3-0.4-0.4-0.6c-8.2-10.1-18.5-17.9-30.2-23c-0.3-0.1-0.6-0.3-1-0.4c-1.9-0.8-3.8-1.5-5.7-2.1c-0.7-0.2-1.4-0.5-2.1-0.7\n\\tc-1.7-0.5-3.4-0.9-5.1-1.3c-0.9-0.2-1.9-0.5-2.8-0.7c-0.5-0.1-0.9-0.2-1.4-0.3c-1.3-0.2-2.6-0.3-3.8-0.5c-0.9-0.1-1.8-0.3-2.6-0.3\n\\tc-2.1-0.2-4.3-0.3-6.4-0.3c-0.4,0-0.8-0.1-1.2-0.1c-0.1,0-0.1,0-0.2,0c-16.4,0-32.4,5-46.2,14.8C49,35,48,41.1,51,45.6\n\\tc3.1,4.4,9.1,5.5,13.5,2.4c10.6-7.5,23-11.3,35.7-11.2c1.8,0,3.6,0.1,5.4,0.3c0.6,0.1,1.1,0.1,1.6,0.2c1.5,0.2,2.9,0.4,4.3,0.7\n\\tc0.6,0.1,1.3,0.3,1.9,0.4c1.4,0.3,2.8,0.7,4.2,1.1c0.4,0.1,0.9,0.3,1.3,0.4c1.6,0.5,3.1,1.1,4.6,1.7c0.2,0.1,0.3,0.1,0.5,0.2\n\\tc9,3.9,17,10,23.2,17.6c0,0,0.1,0.1,0.1,0.2c8.7,10.7,14,24.5,14,39.4H147c-0.4,0-0.7,0.2-0.9,0.5c-0.2,0.3-0.2,0.8,0,1.1l24,36.4\n\\tc0.2,0.3,0.5,0.5,0.9,0.5c0.4,0,0.7-0.2,0.9-0.5l23.9-36.4c0.2-0.3,0.2-0.7,0-1.1c-0.2-0.3-0.5-0.5-0.9-0.5L180.6,98.9L180.6,98.9\n\\tL180.6,98.9z\"/>\n </svg>`,\n})\nexport class RefreshIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'loading-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" [attr.width]=\"width\" [attr.height]=\"height\">\n <circle cx=\"50\" cy=\"36.8101\" r=\"10\">\n <animate attributeName=\"cy\" dur=\"1s\" repeatCount=\"indefinite\" calcMode=\"spline\" keySplines=\"0.45 0 0.9 0.55;0 0.45 0.55 0.9\" keyTimes=\"0;0.5;1\" values=\"23;77;23\"></animate>\n </circle>\n </svg>`,\n})\nexport class LoadingIconComponent {\n @Input()\n width = 84\n\n @Input()\n height = 84\n}\n","import {Component, Input, ViewEncapsulation} from '@angular/core'\nimport {ClickConfig, ClickData, ClickDot, ClickEvent, defaultClickConfig, defaultData} from \"./click-instance\";\nimport {getDomXY, mergeTo} from \"../../helper/helper\";\n\n@Component({\n selector: 'go-captcha-click',\n templateUrl: 'click.component.html',\n styleUrls: ['click.component.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class ClickComponent {\n localConfig?: ClickConfig = defaultClickConfig()\n localData: ClickData = defaultData() as ClickData\n localEvents?: ClickEvent = {}\n\n dots: Array<ClickDot> = []\n\n @Input()\n set config(config: ClickConfig) {\n mergeTo(this.localConfig, config)\n this.localConfig = config\n }\n\n @Input()\n set data(data: ClickData) {\n mergeTo(this.localData, data)\n this.localData = data\n }\n\n @Input()\n set events(events: ClickEvent) {\n mergeTo(this.localEvents, events)\n this.localEvents = events\n }\n\n get hasDisplayWrapperState() {\n return (this.localConfig.width || 0) > 0 || (this.localConfig.height || 0) > 0\n }\n\n get hasDisplayImageState() {\n return (this.localData.image && this.localData.image.length > 0) || (this.localData.thumb && this.localData.thumb.length > 0)\n }\n\n clickEvent(e: Event|any){\n const dom = e.currentTarget\n const xy = getDomXY(dom)\n\n const mouseX = e.pageX || e.clientX\n const mouseY = e.pageY || e.clientY\n\n const domX = xy.domX\n const domY = xy.domY\n\n const xPos = mouseX - domX;\n const yPos = mouseY - domY;\n\n const xx = parseInt(xPos.toString())\n const yy = parseInt(yPos.toString())\n const date = new Date()\n const index = this.dots.length\n\n this.dots.push({key: date.getTime(), index: index + 1, x: xx, y: yy})\n\n this.localEvents.click && this.localEvents.click(xx, yy)\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n confirmEvent(e: Event|any) {\n const dotsStr = JSON.stringify(this.dots)\n let dots: Array<ClickDot> = []\n try {\n dots = JSON.parse(dotsStr)\n } catch (e) {\n console.warn(\"parse dots error\", e)\n }\n\n this.localEvents.confirm && this.localEvents.confirm(dots, () => {\n this.dots = []\n })\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n closeEvent(e: Event|any){\n this.close()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n refreshEvent(e: Event|any) {\n this.refresh()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n reset(){\n this.dots = []\n }\n\n clear(){\n this.reset()\n setTimeout(()=> {\n this.localData.image = ''\n this.localData.thumb = ''\n }, 0)\n }\n\n close() {\n this.localEvents.close && this.localEvents.close()\n this.reset()\n }\n\n refresh() {\n this.localEvents.refresh && this.localEvents.refresh()\n this.reset()\n }\n}\n","<div\n class=\"go-captcha gc-wrapper\"\n [class]=\"{'gc-theme': localConfig.showTheme}\"\n [style]=\"{\n width: (localConfig.width || 0) + ( localConfig.horizontalPadding * 2) + (localConfig.showTheme ? 2 : 0) + 'px',\n paddingLeft: localConfig.horizontalPadding + 'px',\n paddingRight: localConfig.horizontalPadding + 'px',\n paddingTop: localConfig.verticalPadding + 'px',\n paddingBottom: localConfig.verticalPadding + 'px',\n display: hasDisplayWrapperState ? 'block' : 'none'\n }\"\n >\n <div class=\"gc-header\">\n <span>{{ localConfig.title }}</span>\n <img\n [class]=\"{'gc-hide': localData.thumb == ''}\"\n [style]=\"{\n width: localConfig.thumbWidth + 'px',\n height: localConfig.thumbHeight + 'px'\n }\"\n [attr.src]=\"localData.thumb\"\n alt=\"\"\n />\n </div>\n <div\n class=\"gc-body\"\n [style]=\"{\n width: localConfig.width + 'px',\n height: localConfig.height + 'px',\n }\"\n >\n <div class=\"gc-loading\">\n <loading-icon></loading-icon>\n </div>\n <img\n class=\"gc-picture\"\n [class]=\"{'gc-hide': localData.image == ''}\"\n [style]=\"{\n width: localConfig.width + 'px',\n height: localConfig.height + 'px',\n display: hasDisplayImageState ? 'block' : 'none'\n }\"\n [attr.src]=\"localData.image\"\n alt=\"\"\n (click)=\"clickEvent($event)\"\n />\n <div class=\"gc-dots\">\n <div\n class=\"gc-dot\"\n *ngFor=\"let dot of dots;\"\n [style]=\"{\n top: (dot.y - 11) + 'px',\n left: (dot.x - 11) + 'px',\n }\"\n >{{dot.index}}</div>\n </div>\n </div>\n <div class=\"gc-footer\">\n <div class=\"gc-icon-block gc-icon-block2\">\n <close-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"closeEvent($event)\"\n ></close-icon>\n <refresh-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"refreshEvent($event)\"\n ></refresh-icon>\n </div>\n <div class=\"gc-button-block\">\n <button\n [class]=\"{'disabled': !hasDisplayImageState}\"\n (click)=\"confirmEvent($event)\"\n >{{ localConfig.buttonText }}</button>\n </div>\n </div>\n</div>","/**\n * @Author Awen\n * @Date 2024/06/01\n * @Email wengaolng@gmail.com\n **/\n\nexport interface SlideRef {\n reset: () => void,\n clear: () => void,\n refresh: () => void,\n close: () => void,\n}\n\nexport interface SlideConfig {\n width?: number;\n height?: number;\n thumbWidth?: number;\n thumbHeight?: number;\n verticalPadding?: number;\n horizontalPadding?: number;\n showTheme?: boolean;\n title?: string;\n iconSize?: number;\n scope ?: boolean;\n}\n\nexport const defaultSlideConfig = ():SlideConfig => ({\n width: 300,\n height: 220,\n thumbWidth: 150,\n thumbHeight: 40,\n verticalPadding: 16,\n horizontalPadding: 12,\n showTheme: true,\n title: \"请拖动滑块完成拼图\",\n iconSize: 22,\n scope: true,\n})\n\nexport interface SlideData {\n thumbX: number;\n thumbY: number;\n thumbWidth: number;\n thumbHeight: number;\n image: string;\n thumb: string;\n}\n\nexport const defaultSlideData = ():SlideData => ({\n thumbX: 0,\n thumbY: 0,\n thumbHeight: 0,\n thumbWidth: 0,\n image: '',\n thumb: '',\n})\n\nexport interface SlidePoint {\n x: number,\n y: number,\n}\n\nexport interface SlideEvent {\n move?: (x: number, y: number) => void;\n refresh?: () => void;\n close?: () => void;\n confirm?: (point: SlidePoint, clear:(fn: Function) => void) => void;\n}\n\nexport interface SlideInstance {\n data: SlideData,\n config?: SlideConfig;\n events?: SlideEvent,\n}\n","import {Component, Input} from '@angular/core';\n\n@Component({\n selector: 'arrows-icon',\n template: `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 200 200\" [attr.width]=\"width\" [attr.height]=\"height\">\n <path d=\"M131.6,116.3c0,0-75.6,0-109.7,0c-9.1,0-16.2-7.4-16.2-16.2c0-9.1,7.4-16.2,16.2-16.2c28.7,0,109.7,0,109.7,0\n\\ts-5.4-5.4-30.4-30.7c-6.4-6.4-6.4-16.7,0-23.1s16.7-6.4,23.1,0l58.4,58.4c6.4,6.4,6.4,16.7,0,23.1c0,0-32.9,32.9-57.9,57.9\n\\tc-6.4,6.4-16.7,6.4-23.1,0c-6.4-6.4-6.4-16.7,0-23.1C121.8,126.2,131.6,116.3,131.6,116.3z\"/>\n </svg>`,\n})\nexport class ArrowsIconComponent {\n @Input()\n width = 20\n\n @Input()\n height = 20\n}\n","import {Component, ElementRef, Input, SimpleChanges, ViewChild, ViewEncapsulation} from '@angular/core'\nimport {checkTargetFather, mergeTo, mergeToOver} from \"../../helper/helper\";\nimport {defaultSlideConfig, defaultSlideData, SlideConfig, SlideData, SlideEvent} from \"./slide-instance\";\n\n@Component({\n selector: 'go-captcha-slide',\n templateUrl: 'slide.component.html',\n styleUrls: ['slide.component.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class SlideComponent {\n localConfig?: SlideConfig = {...defaultSlideConfig()}\n localData: SlideData = {...defaultSlideData()}\n localEvents?: SlideEvent = {}\n\n @ViewChild('rootRef', {static: false})\n rootRef: ElementRef\n\n @ViewChild('containerRef', {static: false})\n containerRef: ElementRef\n\n @ViewChild('dragBlockRef', {static: false})\n dragBlockRef: ElementRef\n\n @ViewChild('dragBarRef', {static: false})\n dragBarRef: ElementRef\n\n @ViewChild('tileRef', {static: false})\n tileRef: ElementRef\n\n state: {dragLeft: number, thumbLeft: number} = {dragLeft: 0, thumbLeft: this.localData.thumbX || 0}\n isFreeze: boolean = false\n\n @Input()\n set config(config: SlideConfig) {\n mergeTo(this.localConfig, config)\n this.localConfig = config\n }\n\n @Input()\n set data(data: SlideData) {\n mergeTo(this.localData, data)\n this.localData = data\n this.updateState()\n }\n\n @Input()\n set events(events: SlideEvent) {\n mergeTo(this.localEvents, events)\n this.localEvents = events\n }\n\n get hasDisplayWrapperState() {\n return (this.localConfig.width || 0) > 0 || (this.localConfig.height || 0) > 0\n }\n\n get hasDisplayImageState() {\n return (this.localData.image && this.localData.image.length > 0) || (this.localData.thumb && this.localData.thumb.length > 0)\n }\n\n private dsFn = (event: any) => event.preventDefault()\n ngAfterViewInit() {\n this.dragBlockRef.nativeElement && this.dragBlockRef.nativeElement.addEventListener('dragstart', this.dsFn);\n }\n\n ngOnDestroy() {\n this.dragBlockRef.nativeElement && this.dragBlockRef.nativeElement.removeEventListener('dragstart', this.dsFn);\n }\n\n updateState() {\n if (!this.isFreeze) {\n this.state.thumbLeft = (this.localData.thumbX || 0)\n }\n }\n\n dragEvent (e: Event|any) {\n if (!checkTargetFather(this.dragBarRef.nativeElement, e)) {\n return\n }\n\n const touch = e.touches && e.touches[0];\n const offsetLeft = this.dragBlockRef.nativeElement.offsetLeft\n const width = this.containerRef.nativeElement.offsetWidth\n const blockWidth = this.dragBlockRef.nativeElement.offsetWidth\n const maxWidth = width - blockWidth\n\n const tileWith = this.tileRef.nativeElement.offsetWidth\n const tileOffsetLeft = this.tileRef.nativeElement.offsetLeft\n const containerMaxWidth = width - tileWith\n const tileMaxWith = width - (tileWith + tileOffsetLeft)\n const ratio = tileMaxWith / maxWidth\n\n let isMoving = false\n let tmpLeaveDragEvent: Event|any = null\n let startX = 0\n let currentThumbX = 0\n if (touch) {\n startX = touch.pageX - offsetLeft\n } else {\n startX = e.clientX - offsetLeft\n }\n\n const moveEvent = (e: Event|any) => {\n isMoving = true\n const mTouche = e.touches && e.touches[0];\n\n let left = 0;\n if (mTouche) {\n left = mTouche.pageX - startX\n } else {\n left = e.clientX - startX\n }\n\n const ctX = tileOffsetLeft + (left * ratio)\n if (left >= maxWidth) {\n this.state.dragLeft = maxWidth\n currentThumbX = containerMaxWidth\n this.state.thumbLeft = currentThumbX\n return\n }\n\n if (left <= 0) {\n this.state.dragLeft = 0\n currentThumbX = tileOffsetLeft\n this.state.thumbLeft = currentThumbX\n return\n }\n\n this.state.dragLeft = left\n currentThumbX = currentThumbX = ctX\n this.state.thumbLeft = currentThumbX\n\n this.localEvents.move && this.localEvents.move(currentThumbX, this.localData.thumbY || 0)\n\n e.cancelBubble = true\n e.preventDefault()\n }\n\n const upEvent = (e: Event|any) => {\n if (!checkTargetFather(this.dragBarRef.nativeElement, e)) {\n return\n }\n\n clearEvent()\n if (!isMoving) {\n return\n }\n\n isMoving = false\n\n if (currentThumbX < 0) {\n return\n }\n\n this.localEvents.confirm && this.localEvents.confirm({x: parseInt(currentThumbX.toString()), y: this.localData.thumbY || 0}, () => {\n this.reset()\n })\n\n e.cancelBubble = true\n e.preventDefault()\n }\n\n const leaveDragBlockEvent = (e: Event|any) => {\n tmpLeaveDragEvent = e\n }\n\n const enterDragBlockEvent = () => {\n tmpLeaveDragEvent = null\n }\n\n const leaveUpEvent = (_: Event|any) => {\n if(!tmpLeaveDragEvent) {\n return\n }\n\n upEvent(tmpLeaveDragEvent)\n clearEvent()\n }\n\n const scope = this.localConfig.scope\n const dragDom = scope ? this.rootRef.nativeElement : this.dragBarRef.nativeElement\n const scopeDom = scope ? this.rootRef.nativeElement : document.body\n\n const clearEvent = () => {\n scopeDom.removeEventListener(\"mousemove\", moveEvent, false)\n scopeDom.removeEventListener(\"touchmove\", moveEvent, { passive: false })\n\n dragDom.removeEventListener( \"mouseup\", upEvent, false)\n dragDom.removeEventListener( \"mouseenter\", enterDragBlockEvent, false)\n dragDom.removeEventListener( \"mouseleave\", leaveDragBlockEvent, false)\n dragDom.removeEventListener(\"touchend\", upEvent, false)\n\n scopeDom.removeEventListener(\"mouseleave\", upEvent, false)\n scopeDom.removeEventListener(\"mouseup\", leaveUpEvent, false)\n this.isFreeze = false\n }\n this.isFreeze = true\n\n scopeDom.addEventListener(\"mousemove\", moveEvent, false)\n scopeDom.addEventListener(\"touchmove\", moveEvent, { passive: false })\n\n dragDom.addEventListener( \"mouseup\", upEvent, false)\n dragDom.addEventListener( \"mouseenter\", enterDragBlockEvent, false)\n dragDom.addEventListener( \"mouseleave\", leaveDragBlockEvent, false)\n dragDom.addEventListener(\"touchend\", upEvent, false)\n\n scopeDom.addEventListener(\"mouseleave\", upEvent, false)\n scopeDom.addEventListener(\"mouseup\", leaveUpEvent, false)\n }\n\n closeEvent(e: Event|any){\n this.close()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n refreshEvent(e: Event|any) {\n this.refresh()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n reset(){\n this.state.dragLeft = 0\n this.state.thumbLeft = this.localData.thumbX || 0\n }\n\n clear(){\n this.reset()\n setTimeout(()=> {\n this.localData.image = ''\n this.localData.thumb = ''\n this.localData.thumbX = 0\n this.localData.thumbY = 0\n this.localData.thumbHeight = 0\n this.localData.thumbWidth = 0\n }, 0)\n }\n\n close() {\n this.localEvents.close && this.localEvents.close()\n this.reset()\n }\n\n refresh() {\n this.localEvents.refresh && this.localEvents.refresh()\n this.reset()\n }\n}\n","<div\n class=\"go-captcha gc-wrapper\"\n [class]=\"{'gc-theme': localConfig.showTheme}\"\n [style]=\"{\n width: (localConfig.width || 0) + ( localConfig.horizontalPadding * 2) + (localConfig.showTheme ? 2 : 0) + 'px',\n paddingLeft: localConfig.horizontalPadding + 'px',\n paddingRight: localConfig.horizontalPadding + 'px',\n paddingTop: localConfig.verticalPadding + 'px',\n paddingBottom: localConfig.verticalPadding + 'px',\n display: hasDisplayWrapperState ? 'block' : 'none'\n }\"\n #rootRef\n>\n <div class=\"gc-header\">\n <span>{{ localConfig.title }}</span>\n <div class=\"gc-icon-block\">\n <close-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"closeEvent($event)\"\n ></close-icon>\n <refresh-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"refreshEvent($event)\"\n ></refresh-icon>\n </div>\n </div>\n <div\n class=\"gc-body\"\n #containerRef\n [style]=\"{\n width: localConfig.width + 'px',\n height: localConfig.height + 'px'\n }\"\n >\n <div class=\"gc-loading\">\n <loading-icon></loading-icon>\n </div>\n <img\n class=\"gc-picture\"\n [class]=\"{'gc-hide': localData.image == ''}\"\n [style]=\"{display: hasDisplayImageState ? 'block' : 'none'}\"\n [attr.src]=\"localData.image\"\n alt=\"\"\n />\n <div\n class=\"gc-tile\"\n #tileRef\n [style]=\"{\n width: localData.thumbWidth + 'px',\n height: localData.thumbHeight + 'px',\n top: localData.thumbY + 'px',\n left: state.thumbLeft + 'px'\n }\"\n >\n <img\n [class]=\"{'gc-hide': localData.thumb == ''}\"\n [attr.src]=\"localData.thumb\"\n [style]=\"{display: hasDisplayImageState ? 'block' : 'none'}\"\n alt=\"\"\n />\n </div>\n </div>\n <div class=\"gc-footer\">\n <div class=\"gc-drag-slide-bar\" #dragBarRef>\n <div class=\"gc-drag-line\"></div>\n <div\n class=\"gc-drag-block\"\n #dragBlockRef\n (mousedown)=\"dragEvent($event)\"\n [style]=\"{left: state.dragLeft + 'px'}\"\n [class]=\"{'disabled': !hasDisplayImageState}\"\n >\n <div class=\"drag-block-inline\" (touchstart)=\"dragEvent($event)\">\n <arrows-icon></arrows-icon>\n </div>\n </div>\n </div>\n </div>\n</div>","/**\n * @Author Awen\n * @Date 2024/06/01\n * @Email wengaolng@gmail.com\n **/\n\nexport interface SlideRegionRef {\n reset: () => void,\n clear: () => void,\n refresh: () => void,\n close: () => void,\n}\n\nexport interface SlideRegionConfig {\n width?: number;\n height?: number;\n verticalPadding?: number;\n horizontalPadding?: number;\n showTheme?: boolean;\n title?: string;\n iconSize?: number;\n scope ?: boolean;\n}\n\nexport const defaultSlideRegionConfig = ():SlideRegionConfig => ({\n width: 300,\n height: 220,\n verticalPadding: 16,\n horizontalPadding: 12,\n showTheme: true,\n title: \"请拖动滑块完成拼图\",\n iconSize: 22,\n scope: true,\n})\n\nexport interface SlideRegionData {\n thumbX: number;\n thumbY: number;\n thumbWidth: number;\n thumbHeight: number;\n image: string;\n thumb: string;\n}\n\nexport interface SlideRegionPoint {\n x: number,\n y: number,\n}\n\nexport interface SlideRegionEvent {\n move?: (x: number, y: number) => void;\n refresh?: () => void;\n close?: () => void;\n confirm?: (point: SlideRegionPoint, clear:(fn: Function) => void) => void;\n}\n\nexport interface SlideRegionInstance {\n data: SlideRegionData,\n config?: SlideRegionConfig;\n events?: SlideRegionEvent,\n}\n","import {Component, ElementRef, Input, ViewChild, ViewEncapsulation} from '@angular/core'\nimport {checkTargetFather, mergeTo} from \"../../helper/helper\";\nimport {defaultSlideRegionConfig, SlideRegionConfig, SlideRegionData, SlideRegionEvent} from \"./slide-region-instance\";\n\n@Component({\n selector: 'go-captcha-slide-region',\n templateUrl: 'slide-region.component.html',\n styleUrls: ['slide-region.component.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class SlideRegionComponent {\n localConfig?: SlideRegionConfig = defaultSlideRegionConfig()\n localData: SlideRegionData = {\n thumbX: 0,\n thumbY: 0,\n thumbWidth: 0,\n thumbHeight: 0,\n image: \"\",\n thumb: \"\"\n } as SlideRegionData\n localEvents?: SlideRegionEvent = {}\n\n @ViewChild('rootRef', {static: false})\n rootRef: ElementRef\n\n @ViewChild('containerRef', {static: false})\n containerRef: ElementRef\n\n @ViewChild('dragBlockRef', {static: false})\n dragBlockRef: ElementRef\n\n @ViewChild('dragBarRef', {static: false})\n dragBarRef: ElementRef\n\n @ViewChild('tileRef', {static: false})\n tileRef: ElementRef\n\n state: {x: number, y: number} = {x: this.localData.thumbX || 0, y: this.localData.thumbY || 0}\n isFreeze: boolean = false\n\n @Input()\n set config(config: SlideRegionConfig) {\n mergeTo(this.localConfig, config)\n this.localConfig = config\n }\n\n @Input()\n set data(data: SlideRegionData) {\n mergeTo(this.localData, data)\n this.localData = data\n this.updateState()\n }\n\n @Input()\n set events(events: SlideRegionEvent) {\n mergeTo(this.localEvents, events)\n this.localEvents = events\n }\n\n get hasDisplayWrapperState() {\n return (this.localConfig.width || 0) > 0 || (this.localConfig.height || 0) > 0\n }\n\n get hasDisplayImageState() {\n return (this.localData.image && this.localData.image.length > 0) || (this.localData.thumb && this.localData.thumb.length > 0)\n }\n\n private dsFn = (event: any) => event.preventDefault()\n ngAfterViewInit() {\n this.tileRef.nativeElement && this.tileRef.nativeElement.addEventListener('dragstart', this.dsFn);\n }\n\n ngOnDestroy() {\n this.tileRef.nativeElement && this.tileRef.nativeElement.removeEventListener('dragstart', this.dsFn);\n }\n\n updateState() {\n if (!this.isFreeze) {\n this.state.x = (this.localData.thumbX || 0)\n this.state.y = (this.localData.thumbY || 0)\n }\n }\n\n dragEvent(e: Event|any) {\n if (!checkTargetFather(this.containerRef.nativeElement, e)) {\n return\n }\n\n const touch = e.touches && e.touches[0];\n const offsetLeft = this.tileRef.nativeElement.offsetLeft\n const offsetTop = this.tileRef.nativeElement.offsetTop\n const width = this.containerRef.nativeElement.offsetWidth\n const height = this.containerRef.nativeElement.offsetHeight\n const tileWidth = this.tileRef.nativeElement.offsetWidth\n const tileHeight = this.tileRef.nativeElement.offsetHeight\n const maxWidth = width - tileWidth\n const maxHeight = height - tileHeight\n\n let isMoving = false\n let tmpLeaveDragEvent: Event|any = null\n let startX = 0\n let startY = 0\n let tileLeft = 0\n let tileTop = 0\n if (touch) {\n startX = touch.pageX - offsetLeft\n startY = touch.pageY - offsetTop\n } else {\n startX = e.clientX - offsetLeft\n startY = e.clientY - offsetTop\n }\n\n const moveEvent = (e: Event|any) => {\n isMoving = true\n const mTouche = e.touches && e.touches[0];\n\n let left = 0;\n let top = 0;\n if (mTouche) {\n left = mTouche.pageX - startX\n top = mTouche.pageY - startY\n } else {\n left = e.clientX - startX\n top = e.clientY - startY\n }\n\n if (left <= 0) {\n left = 0\n }\n\n if (top <= 0) {\n top = 0\n }\n\n if (left >= maxWidth) {\n left = maxWidth\n }\n\n if (top >= maxHeight) {\n top = maxHeight\n }\n\n this.state.x = left\n this.state.y = top\n tileLeft = left\n tileTop = top\n this.localEvents.move && this.localEvents.move(left, top)\n\n e.cancelBubble = true\n e.preventDefault()\n }\n\n const upEvent = (e: Event|any) => {\n if (!checkTargetFather(this.containerRef.nativeElement, e)) {\n return\n }\n\n clearEvent()\n if (!isMoving) {\n return\n }\n isMoving = false\n\n if (tileLeft < 0 || tileTop < 0) {\n return\n }\n\n this.localEvents.confirm && this.localEvents.confirm({x: tileLeft, y: tileTop}, () => {\n this.reset()\n })\n\n e.cancelBubble = true\n e.preventDefault()\n }\n\n const leaveDragBlockEvent = (e: Event|any) => {\n tmpLeaveDragEvent = e\n }\n\n const enterDragBlockEvent = () => {\n tmpLeaveDragEvent = null\n }\n\n const leaveUpEvent = (_: Event|any) => {\n if(!tmpLeaveDragEvent) {\n return\n }\n\n upEvent(tmpLeaveDragEvent)\n clearEvent()\n }\n\n const scope = this.localConfig.scope\n const dragDom = scope ? this.rootRef.nativeElement : this.dragBarRef.nativeElement\n const scopeDom = scope ? this.rootRef.nativeElement : document.body\n\n const clearEvent = () => {\n scopeDom.removeEventListener(\"mousemove\", moveEvent, false)\n scopeDom.removeEventListener(\"touchmove\", moveEvent, { passive: false })\n\n dragDom.removeEventListener( \"mouseup\", upEvent, false)\n dragDom.removeEventListener( \"mouseenter\", enterDragBlockEvent, false)\n dragDom.removeEventListener( \"mouseleave\", leaveDragBlockEvent, false)\n dragDom.removeEventListener(\"touchend\", upEvent, false)\n\n scopeDom.removeEventListener(\"mouseleave\", upEvent, false)\n scopeDom.removeEventListener(\"mouseup\", leaveUpEvent, false)\n\n this.isFreeze = false\n }\n this.isFreeze = true\n\n scopeDom.addEventListener(\"mousemove\", moveEvent, false)\n scopeDom.addEventListener(\"touchmove\", moveEvent, { passive: false })\n\n dragDom.addEventListener( \"mouseup\", upEvent, false)\n dragDom.addEventListener( \"mouseenter\", enterDragBlockEvent, false)\n dragDom.addEventListener( \"mouseleave\", leaveDragBlockEvent, false)\n dragDom.addEventListener(\"touchend\", upEvent, false)\n\n scopeDom.addEventListener(\"mouseleave\", upEvent, false)\n scopeDom.addEventListener(\"mouseup\", leaveUpEvent, false)\n }\n\n closeEvent(e: Event|any){\n this.close()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n refreshEvent(e: Event|any) {\n this.refresh()\n e.cancelBubble = true\n e.preventDefault()\n return false\n }\n\n reset(){\n this.state.x = this.localData.thumbX || 0\n this.state.y = this.localData.thumbY || 0\n }\n\n clear(){\n this.reset()\n setTimeout(()=> {\n this.localData.image = ''\n this.localData.thumb = ''\n this.localData.thumbX = 0\n this.localData.thumbY = 0\n this.localData.thumbHeight = 0\n this.localData.thumbWidth = 0\n }, 0)\n }\n\n close() {\n this.localEvents.close && this.localEvents.close()\n this.reset()\n }\n\n refresh() {\n this.localEvents.refresh && this.localEvents.refresh()\n this.reset()\n }\n}\n","<div\n class=\"go-captcha gc-wrapper\"\n [class]=\"{'gc-theme': localConfig.showTheme}\"\n [style]=\"{\n width: (localConfig.width || 0) + ( localConfig.horizontalPadding * 2) + (localConfig.showTheme ? 2 : 0) + 'px',\n paddingLeft: localConfig.horizontalPadding + 'px',\n paddingRight: localConfig.horizontalPadding + 'px',\n paddingTop: localConfig.verticalPadding + 'px',\n paddingBottom: localConfig.verticalPadding + 'px',\n display: hasDisplayWrapperState ? 'block' : 'none'\n }\"\n #rootRef\n>\n <div class=\"gc-header gc-header2\">\n <span>{{ localConfig.title }}</span>\n </div>\n <div\n class=\"gc-body\"\n #containerRef\n [style]=\"{width: localConfig.width + 'px', height: localConfig.height + 'px'}\"\n >\n <div class=\"gc-loading\">\n <loading-icon></loading-icon>\n </div>\n <img\n class=\"gc-picture\"\n [class]=\"{'gc-hide': localData.image == ''}\"\n [style]=\"{display: hasDisplayImageState ? 'block' : 'none'}\"\n [attr.src]=\"localData.image\"\n alt=\"\"\n />\n <div\n class=\"gc-tile\"\n #tileRef\n [style]=\"{\n width: localData.thumbWidth + 'px',\n height: localData.thumbHeight + 'px',\n top: state.y + 'px',\n left: state.x + 'px'\n }\"\n (mousedown)=\"dragEvent($event)\"\n (touchstart)=\"dragEvent($event)\"\n >\n <img\n [class]=\"{'gc-hide': localData.thumb == ''}\"\n [style]=\"{display: hasDisplayImageState ? 'block' : 'none'}\"\n [attr.src]=\"localData.thumb\"\n alt=\"\"\n />\n </div>\n </div>\n <div class=\"gc-footer\">\n <div class=\"gc-icon-block\">\n <close-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"closeEvent($event)\"\n ></close-icon>\n <refresh-icon\n [width]=\"localConfig.iconSize\"\n [height]=\"localConfig.iconSize\"\n (click)=\"refreshEvent($event)\"\n ></refresh-icon>\n </div>\n </div>\n</div>","export interface RotateRef {\n reset: () => void,\n clear: () => void,\n refresh: () => void,\n close: () => void,\n}\n\nexport interface RotateConfig {\n width?: number;\n height?: number;\n size?: number;\n verticalPadding?: number;\n horizontalPadding?: number;\n showTheme?: boolean;\n title?: string;\n iconSize?: number;\n scope ?: boolean;\n}\n\nexport const defaultRotateConfig = ():RotateConfig => ({\n width: 300,\n height: 220,\n size: 220,\n verticalPadding: 16,\n horizontalPadding: 12,\n showTheme: true,\n title: \"请拖动滑块完成拼图\",\n iconSize: 22,\n scope: true,\n})\n\nexport interface RotateData {\n angle?: number;\n image: string;\n thumb: string;\n thumbSize?: number;\n}\n\nexport const defaultRotateData = (): RotateData =>({\n angle: 0,\n image: '',\n thumb: '',\n thumbSize: 0\n})\n\n\nexport interface RotateEvent {\n rotate?: (angle: number) => void;\n refresh?: () => void;\n close?: () => void;\n confirm?: (angle: number, clear:(fn: Function) => void) => void;\n}\n\nexport interface RotateInstance {\n data: RotateData,\n config?: RotateConfig;\n events?: RotateEvent,\n}\n","import {Component, ElementRef, Input, ViewChild, ViewEncapsulation} from '@angular/core'\nimport {checkTargetFather, mergeTo} from \"../../helper/helper\";\nimport {defaultRotateConfig, defaultRotateData, RotateConfig, RotateData, RotateEvent} from \"./rotate-instance\";\n\n@Component({\n selector: 'go-captcha-rotate',\n templateUrl: 'rotate.component.html',\n styleUrls: ['rotate.component.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class RotateComponent {\n localConfig?: RotateConfig = defaultRotateConfig()\n localData: RotateData = defaultRotateData()\n localEvents?: RotateEvent = {}\n\n @ViewChild('rootRef', {static: false})\n rootRef: ElementRef\n\n @ViewChild('dragBlockRef', {static: false})\n dragBlockRef: ElementRef\n\n @ViewChild('dragBarRef', {static: false})\n dragBarRef: ElementRef\n\n dragLeft: number = 0\n thumbAngle: number = this.localData.angle || 0\n isFreeze: boolean = false\n\n @Input()\n set config(config: RotateConfig) {\n mergeTo(this.localConfig, config)\n this.localConfig = config\n }\n\n @Input()\n set data(data: RotateData) {\n mergeTo(this.localData, data)\n this.localData = data\n this.updateState()\n }\n\n @Input()\n set events(events: RotateEvent) {\n mergeTo(this.localEvents, events)\n this.localEvents = events\n }\n\n get thumbSizeStyle() {\n return {\n transform: 'rotate('+this.thumbAngle+'deg)',\n ...(this.localData.thumbSize > 0 ? {\n width: this.localData.thumbSize + 'px',\n height: this.localData.thumbSize + 'px'\n } : {})\n }\n }\n\n get hasDisplayWrapperState() {\n return (this.localConfig.width || 0) > 0 || (this.localConfig.height || 0) > 0\n }\n\n get hasDisplayImageState() {\n return (this.localData.image && this.localData.image.length > 0) || (this.localData.thumb && this.localData.thumb.length > 0)\n }\n\n get size() {\n return (this.localConfig.size || 0) > 0 ? this.localConfig.size : defaultRotateConfig().size\n }\n\n private dsFn = (event: any) => event.preventDefault()\n ngAfterViewInit() {\n this.dragBlockRef.nativeElement && this.dragBlockRef.nativeElement.addEventListener('dragstart', this.dsFn);\n }\n\n ngOnDestroy() {\n this.dragBlockRef.nativeElement && this.dragBlockRef.nativeElement.removeEventListener('dragstart', this.dsFn);\n }\n\n updateState() {\n if (!this.isFreeze) {\n this.thumbAngle = (this.localData.angle || 0)\n }\n }\n\n dragEvent = (e: Event|any) => {\n if (!checkTargetFather(this.dragBarRef.nativeElement, e)) {\n return\n }\n\n const touch = e.touches && e.touches[0];\n\n const offsetLeft = this.dragBlockRef.nativeElement.offsetLeft\n const width = this.dragBarRef.nativeElement.offsetWidth\n const blockWidth = this.dragBlockRef.nativeElement.offsetWidth\n const maxWidth = width - blockWidth\n const maxAngle = 360\n const p = (maxAngle - this.localData.angle) / maxWidth\n\n let angle = 0\n let isMoving = false\n let tmpLeaveDragEvent: Event|any = null\n let startX = 0;\n let currentAngle = 0\n if (touch) {\n startX = touch.pageX - offsetLeft\n } else {\n startX = e.clientX - offsetLeft\n }\n\n const moveEvent = (e: Event|any) => {\n isMoving = true\n const mTouche = e.touches && e.touches[0];\n\n let left = 0;\n if (mTouche) {\n left = mTouche.pageX - startX\n } else {\n left = e.clientX - startX\n }\n\n angle = this.localData.angle + (left * p)\n\n if (left >= maxWidth) {\n this.dragLeft = maxWidth\n this.thumbAngle = currentAngle = maxAngle\n return\n }\n\n if (left <= 0) {\n this.dragLeft = 0\n this.thumbAngle = currentAngle = this.localData.angle\n