import { LitElement, html, css } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import * as d3 from 'd3'
@customElement('kpi-mini-trend-chart')
export class KpiMiniTrendChart extends LitElement {
@property({ type: Array }) data: number[] = []
@property({ type: Number }) width: number = 60
@property({ type: Number }) height: number = 30
@property({ type: String }) lineColor: string = '#2196f3'
@property({ type: Number }) strokeWidth: number = 1.5
@property({ type: Boolean }) showPoints: boolean = true
@property({ type: Number }) pointRadius: number = 1.5
static styles = css`
:host {
display: block;
width: 100%;
height: 100%;
}
.mini-chart {
width: 100%;
height: 100%;
background: #f8f9fa;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.trend-line {
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
.data-point {
fill: white;
stroke-width: 1;
}
`
render() {
return html`
`
}
updated() {
this.drawMiniTrend()
}
drawMiniTrend() {
if (!this.data || this.data.length === 0) return
const svg = d3.select(this.renderRoot.querySelector('#mini-trend'))
svg.selectAll('*').remove()
const margin = { top: 2, right: 2, bottom: 2, left: 2 }
const width = this.width - margin.left - margin.right
const height = this.height - margin.top - margin.bottom
// 스케일 설정
const xScale = d3
.scaleLinear()
.domain([0, this.data.length - 1])
.range([0, width])
const yScale = d3
.scaleLinear()
.domain([0, d3.max(this.data) || 100])
.range([height, 0])
// SVG 설정
svg.attr('width', this.width).attr('height', this.height)
const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`)
// 라인 생성기
const line = d3
.line()
.x((d, i) => xScale(i))
.y(d => yScale(d))
.curve(d3.curveMonotoneX)
// 트렌드 라인 그리기
g.append('path')
.datum(this.data)
.attr('class', 'trend-line')
.attr('d', line as any)
.attr('stroke', this.lineColor)
.attr('stroke-width', this.strokeWidth)
// 데이터 포인트 그리기 (첫 번째와 마지막 포인트만)
if (this.showPoints && this.data.length > 0) {
// 첫 번째 포인트
g.append('circle')
.attr('class', 'data-point')
.attr('cx', xScale(0))
.attr('cy', yScale(this.data[0]))
.attr('r', this.pointRadius)
.attr('stroke', '#4caf50')
.attr('fill', 'white')
// 마지막 포인트
if (this.data.length > 1) {
g.append('circle')
.attr('class', 'data-point')
.attr('cx', xScale(this.data.length - 1))
.attr('cy', yScale(this.data[this.data.length - 1]))
.attr('r', this.pointRadius)
.attr('stroke', '#2196f3')
.attr('fill', 'white')
}
}
}
}