gojongwon-circular-progress-bar
Version:
A lightweight, customizable circular progress bar component for web applications
1 lines • 27.3 kB
Source Map (JSON)
{"version":3,"file":"CircularProgressBar.umd.cjs","sources":["../src/CircularProgressBar.ts"],"sourcesContent":["/**\r\n * 색상 타입 정의\r\n */\r\ntype ColorValue = string | ((progress: number) => string);\r\n\r\n/**\r\n * 원형 프로그레스 바의 설정 옵션 인터페이스\r\n */\r\ninterface CircularProgressBarOptions {\r\n value: number; // 현재 값\r\n maxValue: number; // 최대 값\r\n size?: number; // SVG 크기 (픽셀, 기본값: 컨테이너의 최소 크기)\r\n responsive?: boolean; // 반응형 모드 (기본값: false)\r\n gaugeWidth?: number; // 게이지 선 두께 (기본값: 12)\r\n gaugeColor?: ColorValue; // 게이지 색상 (기본값: \"#2196f3\")\r\n gaugeType?: \"round\" | \"flat\"; // 게이지 끝 모양 (기본값: 'round')\r\n trailWidth?: number; // 배경 트레일 선 두께 (기본값: 12)\r\n trailColor?: ColorValue; // 배경 트레일 색상 (기본값: \"#e0e0e0\")\r\n textColor?: string; // 텍스트 색상 (기본값: \"#333\")\r\n text?: string; // 표시할 텍스트 (기본값: 퍼센트)\r\n textSize?: number; // 텍스트 크기 (기본값: 24)\r\n textFont?: string; // 텍스트 폰트 (기본값: \"Arial\")\r\n animate?: boolean; // 애니메이션 활성화 (기본값: true)\r\n duration?: number; // 애니메이션 지속 시간 (기본값: 800ms)\r\n // CSS 클래스 커스터마이징\r\n className?: string; // SVG 요소에 적용할 CSS 클래스명\r\n gaugeClassName?: string; // 게이지 원에 적용할 CSS 클래스명\r\n trailClassName?: string; // 트레일 원에 적용할 CSS 클래스명\r\n textClassName?: string; // 텍스트에 적용할 CSS 클래스명\r\n // 인라인 스타일 비활성화 옵션\r\n disableInlineStyles?: boolean; // 인라인 스타일 비활성화 (기본값: false)\r\n}\r\n\r\n/**\r\n * 원형 프로그레스 바 클래스\r\n * SVG를 사용하여 원형 프로그레스 바를 생성하고 관리합니다.\r\n */\r\nexport class CircularProgressBar {\r\n private container: HTMLElement; // 프로그레스 바가 렌더링될 컨테이너\r\n private options: CircularProgressBarOptions; // 설정 옵션\r\n private svg!: SVGElement; // SVG 요소\r\n private gauge!: SVGPathElement; // 게이지 원 (진행률 표시)\r\n private trail!: SVGPathElement; // 트레일 원 (배경)\r\n private text!: SVGTextElement; // 텍스트 요소\r\n private resizeObserver?: ResizeObserver; // 컨테이너 크기 변화 감지용\r\n private currentSize: number = 0; // 현재 SVG 크기\r\n\r\n /**\r\n * CircularProgressBar 생성자\r\n * @param container - 프로그레스 바를 렌더링할 HTML 요소\r\n * @param options - 프로그레스 바 설정 옵션\r\n */\r\n constructor(container: HTMLElement, options: CircularProgressBarOptions) {\r\n this.container = container;\r\n // 기본값과 사용자 옵션을 병합\r\n this.options = {\r\n responsive: false,\r\n gaugeWidth: 12,\r\n gaugeColor: \"#2196f3\",\r\n gaugeType: \"round\",\r\n trailWidth: 12,\r\n trailColor: \"#e0e0e0\",\r\n textColor: \"#333\",\r\n textSize: 24,\r\n textFont: \"Arial\",\r\n animate: true,\r\n duration: 800,\r\n disableInlineStyles: false,\r\n ...options,\r\n };\r\n\r\n // 반응형 모드일 때 size가 없으면 컨테이너 크기로 설정\r\n if (this.options.responsive && !this.options.size) {\r\n this.options.size = this.getContainerSize();\r\n }\r\n\r\n this.initialize();\r\n this.render();\r\n\r\n // 반응형 모드일 때 ResizeObserver 설정\r\n if (this.options.responsive) {\r\n this.setupResizeObserver();\r\n }\r\n }\r\n\r\n /**\r\n * 색상 값을 해석합니다.\r\n * 문자열이면 그대로 반환하고, 함수면 현재 진행률을 기반으로 색상을 계산합니다.\r\n * @param colorValue - 색상 값 (문자열 또는 함수)\r\n * @param progress - 현재 진행률 (0~1)\r\n * @returns 해석된 색상 문자열\r\n */\r\n private resolveColor(colorValue: ColorValue, progress: number): string {\r\n if (typeof colorValue === \"function\") {\r\n return colorValue(progress);\r\n }\r\n return colorValue;\r\n }\r\n\r\n /**\r\n * SVG 요소와 원형 프로그레스 바를 초기화합니다.\r\n * 중심은 같고 너비의 중앙만 같도록 반지름을 조정합니다.\r\n */\r\n private initialize() {\r\n // 초기 크기 설정\r\n if (!this.options.size) {\r\n this.options.size = this.getContainerSize();\r\n }\r\n this.currentSize = this.options.size;\r\n\r\n // SVG 요소 생성\r\n this.svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n this.svg.setAttribute(\"width\", this.options.size.toString());\r\n this.svg.setAttribute(\"height\", this.options.size.toString());\r\n this.svg.setAttribute(\"viewBox\", `0 0 ${this.options.size} ${this.options.size}`);\r\n\r\n // CSS 클래스 적용\r\n if (this.options.className) {\r\n this.svg.setAttribute(\"class\", this.options.className);\r\n }\r\n\r\n this.svg.style.transform = \"rotate(-90deg)\"; // 상단에서 시작하도록 -90도 회전\r\n\r\n // 중심점 계산\r\n const centerX = this.options.size / 2;\r\n const centerY = this.options.size / 2;\r\n\r\n // 기본 반지름 계산 (가장 큰 stroke width를 고려하여 여백 확보)\r\n const maxStrokeWidth = Math.max(this.options.gaugeWidth!, this.options.trailWidth!);\r\n const baseRadius = (this.options.size - maxStrokeWidth) / 2;\r\n\r\n // 각 원의 반지름을 개별적으로 계산\r\n // 중심은 같고 각각의 stroke width 중앙이 같은 위치에 오도록 설정\r\n const trailRadius = baseRadius;\r\n const gaugeRadius = baseRadius;\r\n\r\n // 트레일 원 생성 (배경)\r\n this.trail = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n this.trail.setAttribute(\"cx\", centerX.toString());\r\n this.trail.setAttribute(\"cy\", centerY.toString());\r\n this.trail.setAttribute(\"r\", trailRadius.toString());\r\n this.trail.setAttribute(\"fill\", \"none\");\r\n\r\n // CSS 클래스 적용\r\n if (this.options.trailClassName) {\r\n this.trail.setAttribute(\"class\", this.options.trailClassName);\r\n }\r\n\r\n // 인라인 스타일 설정 (비활성화되지 않은 경우에만)\r\n if (!this.options.disableInlineStyles) {\r\n this.trail.setAttribute(\"stroke\", this.resolveColor(this.options.trailColor!, 0));\r\n this.trail.setAttribute(\"stroke-width\", this.options.trailWidth!.toString());\r\n }\r\n\r\n // 게이지 원 생성 (진행률 표시)\r\n this.gauge = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n this.gauge.setAttribute(\"cx\", centerX.toString());\r\n this.gauge.setAttribute(\"cy\", centerY.toString());\r\n this.gauge.setAttribute(\"r\", gaugeRadius.toString());\r\n this.gauge.setAttribute(\"fill\", \"none\");\r\n\r\n // CSS 클래스 적용\r\n if (this.options.gaugeClassName) {\r\n this.gauge.setAttribute(\"class\", this.options.gaugeClassName);\r\n }\r\n\r\n // 인라인 스타일 설정 (비활성화되지 않은 경우에만)\r\n if (!this.options.disableInlineStyles) {\r\n this.gauge.setAttribute(\"stroke\", this.resolveColor(this.options.gaugeColor!, 0));\r\n this.gauge.setAttribute(\"stroke-width\", this.options.gaugeWidth!.toString());\r\n this.gauge.setAttribute(\r\n \"stroke-linecap\",\r\n this.options.gaugeType === \"round\" ? \"round\" : \"butt\"\r\n );\r\n }\r\n\r\n // stroke-dasharray를 원의 둘레로 고정하고 stroke-dashoffset으로 애니메이션 제어\r\n const circumference = 2 * Math.PI * gaugeRadius;\r\n this.gauge.style.strokeDasharray = circumference.toString();\r\n this.gauge.style.strokeDashoffset = circumference.toString(); // 초기값: 진행률 0%\r\n\r\n // 텍스트 컨테이너 그룹 생성\r\n const textGroup = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\");\r\n textGroup.setAttribute(\r\n \"transform\",\r\n `translate(${this.options.size / 2}, ${this.options.size / 2}) rotate(90)`\r\n );\r\n\r\n // 텍스트 요소 생성\r\n this.text = document.createElementNS(\"http://www.w3.org/2000/svg\", \"text\");\r\n\r\n // CSS 클래스 적용\r\n if (this.options.textClassName) {\r\n this.text.setAttribute(\"class\", this.options.textClassName);\r\n }\r\n\r\n // 인라인 스타일 설정 (비활성화되지 않은 경우에만)\r\n if (!this.options.disableInlineStyles) {\r\n this.text.setAttribute(\"fill\", this.options.textColor!);\r\n this.text.setAttribute(\"font-size\", this.options.textSize!.toString());\r\n this.text.setAttribute(\"font-family\", this.options.textFont!);\r\n this.text.setAttribute(\"text-anchor\", \"middle\");\r\n this.text.setAttribute(\"dominant-baseline\", \"middle\");\r\n }\r\n\r\n this.text.setAttribute(\"x\", \"0\");\r\n this.text.setAttribute(\"y\", \"0\");\r\n\r\n // 텍스트를 그룹에 추가\r\n textGroup.appendChild(this.text);\r\n\r\n // SVG에 요소들을 추가\r\n this.svg.appendChild(this.trail);\r\n this.svg.appendChild(this.gauge);\r\n this.svg.appendChild(textGroup);\r\n\r\n // 컨테이너를 비우고 SVG 추가\r\n this.container.innerHTML = \"\";\r\n this.container.appendChild(this.svg);\r\n }\r\n\r\n /**\r\n * 현재 값에 따라 프로그레스 바를 렌더링합니다.\r\n * stroke-dashoffset을 조정하여 진행률을 표시합니다.\r\n */\r\n private render() {\r\n // initialize 메서드와 동일한 반지름 계산 로직 사용\r\n const maxStrokeWidth = Math.max(this.options.gaugeWidth!, this.options.trailWidth!);\r\n const baseRadius = (this.currentSize - maxStrokeWidth) / 2;\r\n const gaugeRadius = baseRadius; // gauge와 trail이 같은 반지름 사용\r\n const circumference = 2 * Math.PI * gaugeRadius; // 원의 둘레\r\n\r\n // 진행률 계산 (0~1 사이 값으로 정규화)\r\n const progress = Math.min(Math.max(this.options.value / this.options.maxValue, 0), 1);\r\n const dashLength = circumference * progress; // 표시할 선의 길이\r\n\r\n // 색상 동적 업데이트 (함수인 경우에만, 인라인 스타일이 활성화된 경우에만)\r\n if (!this.options.disableInlineStyles) {\r\n if (typeof this.options.gaugeColor === \"function\") {\r\n this.gauge.setAttribute(\"stroke\", this.resolveColor(this.options.gaugeColor, progress));\r\n }\r\n if (typeof this.options.trailColor === \"function\") {\r\n this.trail.setAttribute(\"stroke\", this.resolveColor(this.options.trailColor, progress));\r\n }\r\n }\r\n\r\n // 게이지 업데이트 - stroke-dashoffset으로 애니메이션 제어\r\n this.gauge.style.strokeDasharray = circumference.toString();\r\n this.gauge.style.strokeDashoffset = (circumference - dashLength).toString();\r\n\r\n // 애니메이션 설정 (animate 옵션이 true이고 duration이 0보다 클 때만)\r\n if (this.options.animate && this.options.duration! > 0) {\r\n this.gauge.style.transition = `stroke-dashoffset ${this.options.duration}ms ease-in-out`;\r\n } else {\r\n this.gauge.style.transition = \"none\"; // 애니메이션 비활성화\r\n }\r\n\r\n // 텍스트 내용 설정\r\n const displayText = this.options.text ?? `${Math.round(progress * 100)}%`;\r\n this.text.textContent = displayText;\r\n }\r\n\r\n /**\r\n * 프로그레스 바의 값을 설정합니다.\r\n * @param value - 새로운 값 (0 ~ maxValue 사이)\r\n */\r\n public setValue(value: number) {\r\n this.options.value = Math.min(Math.max(value, 0), this.options.maxValue);\r\n this.render();\r\n }\r\n\r\n /**\r\n * 현재 값을 반환합니다.\r\n * @returns 현재 값\r\n */\r\n public getValue(): number {\r\n return this.options.value;\r\n }\r\n\r\n /**\r\n * 컨테이너의 크기를 가져옵니다.\r\n * @returns 컨테이너의 최소 크기 (가로, 세로 중 작은 값)\r\n */\r\n private getContainerSize(): number {\r\n const rect = this.container.getBoundingClientRect();\r\n return Math.min(rect.width, rect.height);\r\n }\r\n\r\n /**\r\n * ResizeObserver를 설정하여 컨테이너 크기 변화를 감지합니다.\r\n */\r\n private setupResizeObserver() {\r\n if (typeof ResizeObserver !== \"undefined\") {\r\n this.resizeObserver = new ResizeObserver(entries => {\r\n for (const entry of entries) {\r\n const newSize = Math.min(entry.contentRect.width, entry.contentRect.height);\r\n if (newSize !== this.currentSize && newSize > 0) {\r\n this.resize(newSize);\r\n }\r\n }\r\n });\r\n this.resizeObserver.observe(this.container);\r\n }\r\n }\r\n\r\n /**\r\n * SVG 크기를 조정합니다.\r\n * @param newSize - 새로운 크기\r\n */\r\n private resize(newSize: number) {\r\n this.currentSize = newSize;\r\n this.options.size = newSize;\r\n\r\n // SVG 크기 업데이트\r\n this.svg.setAttribute(\"width\", newSize.toString());\r\n this.svg.setAttribute(\"height\", newSize.toString());\r\n this.svg.setAttribute(\"viewBox\", `0 0 ${newSize} ${newSize}`);\r\n\r\n // 원들의 위치와 크기 재계산\r\n const maxStrokeWidth = Math.max(this.options.gaugeWidth!, this.options.trailWidth!);\r\n const baseRadius = (newSize - maxStrokeWidth) / 2;\r\n const centerX = newSize / 2;\r\n const centerY = newSize / 2;\r\n\r\n const trailRadius = baseRadius;\r\n const gaugeRadius = baseRadius;\r\n\r\n // 트레일 원 업데이트\r\n this.trail.setAttribute(\"cx\", centerX.toString());\r\n this.trail.setAttribute(\"cy\", centerY.toString());\r\n this.trail.setAttribute(\"r\", trailRadius.toString());\r\n\r\n // 게이지 원 업데이트\r\n this.gauge.setAttribute(\"cx\", centerX.toString());\r\n this.gauge.setAttribute(\"cy\", centerY.toString());\r\n this.gauge.setAttribute(\"r\", gaugeRadius.toString());\r\n\r\n // stroke-dasharray와 stroke-dashoffset 재계산\r\n const circumference = 2 * Math.PI * gaugeRadius;\r\n const progress = Math.min(Math.max(this.options.value / this.options.maxValue, 0), 1);\r\n const dashLength = circumference * progress;\r\n\r\n this.gauge.style.strokeDasharray = circumference.toString();\r\n this.gauge.style.strokeDashoffset = (circumference - dashLength).toString();\r\n\r\n // 리사이즈 시에는 애니메이션을 일시적으로 비활성화하여 부드러운 크기 조정\r\n this.gauge.style.transition = \"none\";\r\n\r\n // 텍스트 그룹 위치 업데이트\r\n const textGroup = this.svg.querySelector(\"g\");\r\n if (textGroup) {\r\n textGroup.setAttribute(\"transform\", `translate(${centerX}, ${centerY}) rotate(90)`);\r\n }\r\n\r\n // 리사이즈 완료 후 애니메이션 설정 복원\r\n setTimeout(() => {\r\n if (this.options.animate && this.options.duration! > 0) {\r\n this.gauge.style.transition = `stroke-dashoffset ${this.options.duration}ms ease-in-out`;\r\n }\r\n }, 0);\r\n }\r\n\r\n /**\r\n * 인스턴스를 정리합니다.\r\n * ResizeObserver를 해제합니다.\r\n */\r\n public destroy() {\r\n if (this.resizeObserver) {\r\n this.resizeObserver.disconnect();\r\n this.resizeObserver = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * 게이지 색상을 동적으로 업데이트합니다.\r\n * @param color - 새로운 색상 (문자열 또는 함수)\r\n */\r\n public setGaugeColor(color: ColorValue) {\r\n this.options.gaugeColor = color;\r\n const progress = Math.min(Math.max(this.options.value / this.options.maxValue, 0), 1);\r\n this.gauge.setAttribute(\"stroke\", this.resolveColor(color, progress));\r\n }\r\n\r\n /**\r\n * 트레일 색상을 동적으로 업데이트합니다.\r\n * @param color - 새로운 색상 (문자열 또는 함수)\r\n */\r\n public setTrailColor(color: ColorValue) {\r\n this.options.trailColor = color;\r\n const progress = Math.min(Math.max(this.options.value / this.options.maxValue, 0), 1);\r\n this.trail.setAttribute(\"stroke\", this.resolveColor(color, progress));\r\n }\r\n\r\n /**\r\n * 현재 게이지 색상을 반환합니다.\r\n * @returns 현재 게이지 색상 설정\r\n */\r\n public getGaugeColor(): ColorValue {\r\n return this.options.gaugeColor!;\r\n }\r\n\r\n /**\r\n * 현재 트레일 색상을 반환합니다.\r\n * @returns 현재 트레일 색상 설정\r\n */\r\n public getTrailColor(): ColorValue {\r\n return this.options.trailColor!;\r\n }\r\n\r\n /**\r\n * SVG 요소에 CSS 클래스를 설정합니다.\r\n * @param className - CSS 클래스명\r\n */\r\n public setClassName(className: string) {\r\n this.options.className = className;\r\n this.svg.setAttribute(\"class\", className);\r\n }\r\n\r\n /**\r\n * 게이지 원에 CSS 클래스를 설정합니다.\r\n * @param className - CSS 클래스명\r\n */\r\n public setGaugeClassName(className: string) {\r\n this.options.gaugeClassName = className;\r\n this.gauge.setAttribute(\"class\", className);\r\n }\r\n\r\n /**\r\n * 트레일 원에 CSS 클래스를 설정합니다.\r\n * @param className - CSS 클래스명\r\n */\r\n public setTrailClassName(className: string) {\r\n this.options.trailClassName = className;\r\n this.trail.setAttribute(\"class\", className);\r\n }\r\n\r\n /**\r\n * 텍스트에 CSS 클래스를 설정합니다.\r\n * @param className - CSS 클래스명\r\n */\r\n public setTextClassName(className: string) {\r\n this.options.textClassName = className;\r\n this.text.setAttribute(\"class\", className);\r\n }\r\n\r\n /**\r\n * 인라인 스타일 활성화/비활성화를 설정합니다.\r\n * @param disable - true면 인라인 스타일 비활성화, false면 활성화\r\n */\r\n public setDisableInlineStyles(disable: boolean) {\r\n this.options.disableInlineStyles = disable;\r\n // 필요시 스타일 재적용\r\n if (!disable) {\r\n this.render();\r\n }\r\n }\r\n\r\n /**\r\n * 현재 CSS 클래스 설정을 반환합니다.\r\n * @returns CSS 클래스 설정 객체\r\n */\r\n public getClassNames() {\r\n return {\r\n className: this.options.className,\r\n gaugeClassName: this.options.gaugeClassName,\r\n trailClassName: this.options.trailClassName,\r\n textClassName: this.options.textClassName,\r\n };\r\n }\r\n\r\n /**\r\n * SVG 요소를 반환합니다.\r\n * 외부에서 직접 스타일링할 때 사용합니다.\r\n * @returns SVG 요소\r\n */\r\n public getSVGElement(): SVGElement {\r\n return this.svg;\r\n }\r\n\r\n /**\r\n * 게이지 원 요소를 반환합니다.\r\n * @returns 게이지 원 요소\r\n */\r\n public getGaugeElement(): SVGPathElement {\r\n return this.gauge;\r\n }\r\n\r\n /**\r\n * 트레일 원 요소를 반환합니다.\r\n * @returns 트레일 원 요소\r\n */\r\n public getTrailElement(): SVGPathElement {\r\n return this.trail;\r\n }\r\n\r\n /**\r\n * 텍스트 요소를 반환합니다.\r\n * @returns 텍스트 요소\r\n */\r\n public getTextElement(): SVGTextElement {\r\n return this.text;\r\n }\r\n}\r\n"],"names":["constructor","container","options","__publicField","this","responsive","gaugeWidth","gaugeColor","gaugeType","trailWidth","trailColor","textColor","textSize","textFont","animate","duration","disableInlineStyles","size","getContainerSize","initialize","render","setupResizeObserver","resolveColor","colorValue","progress","currentSize","svg","document","createElementNS","setAttribute","toString","className","style","transform","centerX","centerY","maxStrokeWidth","Math","max","baseRadius","trailRadius","gaugeRadius","trail","trailClassName","gauge","gaugeClassName","circumference","PI","strokeDasharray","strokeDashoffset","textGroup","text","textClassName","appendChild","innerHTML","min","value","maxValue","dashLength","transition","displayText","round","textContent","setValue","getValue","rect","getBoundingClientRect","width","height","ResizeObserver","resizeObserver","entries","entry","newSize","contentRect","resize","observe","querySelector","setTimeout","destroy","disconnect","setGaugeColor","color","setTrailColor","getGaugeColor","getTrailColor","setClassName","setGaugeClassName","setTrailClassName","setTextClassName","setDisableInlineStyles","disable","getClassNames","getSVGElement","getGaugeElement","getTrailElement","getTextElement"],"mappings":"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"}