@operato/gantt 7.1.27 → 7.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/.editorconfig +0 -29
- package/.storybook/main.js +0 -3
- package/.storybook/preview.js +0 -52
- package/.storybook/server.mjs +0 -8
- package/demo/index.html +0 -22
- package/src/draw-time-scale-header.ts +0 -142
- package/src/gantt-chart-controller.ts +0 -336
- package/src/index.ts +0 -0
- package/src/locales.ts +0 -78
- package/src/ox-gantt-chart.ts +0 -518
- package/src/ox-gantt-resize-splitter.ts +0 -131
- package/src/ox-gantt.ts +0 -532
- package/src/ox-resource-chart.ts +0 -145
- package/src/ox-task-tooltip.ts +0 -120
- package/src/resource-chart-controller.ts +0 -284
- package/src/types.ts +0 -32
- package/src/utils.ts +0 -13
- package/stories/ox-gantt-chart.stories.ts +0 -125
- package/stories/ox-gantt.stories.ts +0 -417
- package/tsconfig.json +0 -25
- package/web-dev-server.config.mjs +0 -27
- package/web-test-runner.config.mjs +0 -41
package/src/ox-task-tooltip.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit'
|
|
2
|
-
import { customElement, property } from 'lit/decorators.js'
|
|
3
|
-
|
|
4
|
-
@customElement('ox-task-tooltip')
|
|
5
|
-
export class OxTaskTooltip extends LitElement {
|
|
6
|
-
static styles = css`
|
|
7
|
-
:host {
|
|
8
|
-
position: fixed; /* position: absolute로 변경 */
|
|
9
|
-
background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface-variant, #f9f9f9));
|
|
10
|
-
border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));
|
|
11
|
-
padding: var(--spacing-medium, 10px);
|
|
12
|
-
border-radius: var(--spacing-medium, 8px);
|
|
13
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
14
|
-
visibility: hidden;
|
|
15
|
-
z-index: 10;
|
|
16
|
-
max-width: 300px;
|
|
17
|
-
font-family: Roboto;
|
|
18
|
-
font-size: 14px;
|
|
19
|
-
line-height: 1.6;
|
|
20
|
-
color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
|
|
21
|
-
transition:
|
|
22
|
-
visibility 0.1s,
|
|
23
|
-
opacity 0.1s;
|
|
24
|
-
opacity: 0; /* 초기에는 보이지 않음 */
|
|
25
|
-
}
|
|
26
|
-
:host([visible]) {
|
|
27
|
-
visibility: visible;
|
|
28
|
-
opacity: 1; /* 보일 때는 불투명 */
|
|
29
|
-
}
|
|
30
|
-
.title {
|
|
31
|
-
font-weight: bold;
|
|
32
|
-
font-size: 16px;
|
|
33
|
-
margin-bottom: 8px;
|
|
34
|
-
color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */
|
|
35
|
-
}
|
|
36
|
-
.detail {
|
|
37
|
-
display: grid;
|
|
38
|
-
grid-template-columns: auto auto 1fr;
|
|
39
|
-
gap: 4px;
|
|
40
|
-
align-items: center;
|
|
41
|
-
}
|
|
42
|
-
.label {
|
|
43
|
-
font-weight: bold;
|
|
44
|
-
color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
|
|
45
|
-
text-align: right; /* 라벨을 우측 정렬 */
|
|
46
|
-
}
|
|
47
|
-
.colon {
|
|
48
|
-
text-align: center;
|
|
49
|
-
color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
|
|
50
|
-
}
|
|
51
|
-
.value {
|
|
52
|
-
text-align: left; /* 값을 좌측 정렬 */
|
|
53
|
-
color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
|
|
54
|
-
}
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
@property({ type: String }) title = ''
|
|
58
|
-
@property({ type: String }) startDate = ''
|
|
59
|
-
@property({ type: String }) endDate = ''
|
|
60
|
-
@property({ type: Number }) progress = 0
|
|
61
|
-
@property({ type: String }) type = ''
|
|
62
|
-
|
|
63
|
-
show(x: number, y: number) {
|
|
64
|
-
const tooltipWidth = this.offsetWidth
|
|
65
|
-
const tooltipHeight = this.offsetHeight
|
|
66
|
-
const offsetX = 10
|
|
67
|
-
const offsetY = 10
|
|
68
|
-
|
|
69
|
-
// 기본 위치 계산
|
|
70
|
-
let left = x + offsetX
|
|
71
|
-
let top = y + offsetY
|
|
72
|
-
|
|
73
|
-
// 화면 경계 확인 및 조정
|
|
74
|
-
const screenWidth = window.innerWidth
|
|
75
|
-
const screenHeight = window.innerHeight
|
|
76
|
-
|
|
77
|
-
if (left + tooltipWidth > screenWidth) {
|
|
78
|
-
left = x - tooltipWidth - offsetX
|
|
79
|
-
}
|
|
80
|
-
if (top + tooltipHeight > screenHeight) {
|
|
81
|
-
top = y - tooltipHeight - offsetY
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// offsetParent 요소를 기준으로 위치 설정
|
|
85
|
-
if (this.offsetParent) {
|
|
86
|
-
const parentRect = this.offsetParent!.getBoundingClientRect()
|
|
87
|
-
this.style.left = `${left - parentRect.left}px`
|
|
88
|
-
this.style.top = `${top - parentRect.top}px`
|
|
89
|
-
} else {
|
|
90
|
-
this.style.left = `${left}px`
|
|
91
|
-
this.style.top = `${top}px`
|
|
92
|
-
|
|
93
|
-
const myRect = this.getBoundingClientRect()
|
|
94
|
-
|
|
95
|
-
/* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */
|
|
96
|
-
if (myRect.left !== left || myRect.top !== top) {
|
|
97
|
-
this.style.left = `${left + (left - myRect.left)}px`
|
|
98
|
-
this.style.top = `${top + (top - myRect.top)}px`
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.setAttribute('visible', '')
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
hide() {
|
|
106
|
-
this.removeAttribute('visible')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
render() {
|
|
110
|
-
return html`
|
|
111
|
-
<div class="title">${this.title}</div>
|
|
112
|
-
<div class="detail">
|
|
113
|
-
<span class="label">Type</span><span class="colon">:</span><span class="value">${this.type}</span>
|
|
114
|
-
<span class="label">Start Date</span><span class="colon">:</span><span class="value">${this.startDate}</span>
|
|
115
|
-
<span class="label">End Date</span><span class="colon">:</span><span class="value">${this.endDate}</span>
|
|
116
|
-
<span class="label">Progress</span><span class="colon">:</span><span class="value">${this.progress}%</span>
|
|
117
|
-
</div>
|
|
118
|
-
`
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'
|
|
2
|
-
import * as d3 from 'd3'
|
|
3
|
-
import { TimeScale, Task, Resource } from './types'
|
|
4
|
-
import { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header'
|
|
5
|
-
|
|
6
|
-
export class ResourceChartController implements ReactiveController {
|
|
7
|
-
private host: ReactiveControllerHost & LitElement
|
|
8
|
-
private fromTime: Date
|
|
9
|
-
private toTime: Date
|
|
10
|
-
private totalDays: number
|
|
11
|
-
private _timeScale?: d3.ScaleTime<number, number, never>
|
|
12
|
-
|
|
13
|
-
private touchStartY?: number
|
|
14
|
-
private touchStartX?: number
|
|
15
|
-
private scrollStartX?: number
|
|
16
|
-
private scrollStartY?: number
|
|
17
|
-
|
|
18
|
-
public baseWidth: number = 30
|
|
19
|
-
public level: TimeScale
|
|
20
|
-
public resources: Resource[] = []
|
|
21
|
-
public tasks: Task[] = []
|
|
22
|
-
|
|
23
|
-
constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale) {
|
|
24
|
-
this.host = host
|
|
25
|
-
this.fromTime = new Date(fromDate)
|
|
26
|
-
this.toTime = new Date(toDate)
|
|
27
|
-
this.level = axisScale
|
|
28
|
-
this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
|
|
29
|
-
this.host.addController(this)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
hostConnected() {
|
|
33
|
-
this.updateTimeScale()
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get timeScale() {
|
|
37
|
-
if (!this._timeScale) {
|
|
38
|
-
this._timeScale = d3
|
|
39
|
-
.scaleTime()
|
|
40
|
-
.domain([d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1)])
|
|
41
|
-
.range([0, this.getChartWidth()])
|
|
42
|
-
}
|
|
43
|
-
return this._timeScale
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public syncTimeScale(detail: { baseWidth: number; level: TimeScale }) {
|
|
47
|
-
this.baseWidth = detail.baseWidth
|
|
48
|
-
this.level = detail.level
|
|
49
|
-
|
|
50
|
-
this.updateTimeScale()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
updateRange(fromDate: string, toDate: string) {
|
|
54
|
-
this.fromTime = new Date(fromDate)
|
|
55
|
-
this.toTime = new Date(toDate)
|
|
56
|
-
this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
|
|
57
|
-
this._timeScale = undefined
|
|
58
|
-
this.host.requestUpdate()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
setResources(resources: Resource[]) {
|
|
62
|
-
this.resources = resources
|
|
63
|
-
this.host.requestUpdate()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
setTasks(tasks: Task[]) {
|
|
67
|
-
this.tasks = tasks
|
|
68
|
-
this.host.requestUpdate()
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
updateTimeScale() {
|
|
72
|
-
this.timeScale.range([0, this.getChartWidth()])
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
getScale() {
|
|
76
|
-
return getScale(this.level)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
getChartWidth() {
|
|
80
|
-
return getChartWidth(this.fromTime, this.toTime, this.baseWidth, this.level)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
drawAxes(svgHeader: SVGElement) {
|
|
84
|
-
drawTimeScaleHeader(svgHeader, this.timeScale, this.fromTime, this.toTime, this.baseWidth, this.level, false)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
drawBody(svgBody: SVGElement) {
|
|
88
|
-
const body = d3.select(svgBody)
|
|
89
|
-
|
|
90
|
-
body.selectAll('*').remove()
|
|
91
|
-
body.attr('width', this.getChartWidth())
|
|
92
|
-
|
|
93
|
-
if (this.resources.length > 0) {
|
|
94
|
-
const chartHeight = this.resources.length * 30
|
|
95
|
-
|
|
96
|
-
const addGridLines = (ticks: Date[]) => {
|
|
97
|
-
ticks.forEach(tick => {
|
|
98
|
-
const startX = this.timeScale(tick)
|
|
99
|
-
body
|
|
100
|
-
.append('line')
|
|
101
|
-
.attr('x1', startX)
|
|
102
|
-
.attr('x2', startX)
|
|
103
|
-
.attr('y1', 0)
|
|
104
|
-
.attr('y2', chartHeight) // Ensure vertical lines extend to the bottom
|
|
105
|
-
.attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
|
|
106
|
-
.attr('stroke-width', 1)
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let ticks
|
|
111
|
-
if (this.level === 'week-day') {
|
|
112
|
-
ticks = d3.timeDay.every(1)!.range(d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1))
|
|
113
|
-
} else if (this.level === 'quarter-week') {
|
|
114
|
-
ticks = d3.timeWeek.every(1)!.range(d3.timeWeek.floor(this.fromTime), d3.timeWeek.offset(this.toTime, 1))
|
|
115
|
-
} else if (this.level === 'year-month') {
|
|
116
|
-
ticks = d3.timeMonth.every(1)!.range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 1))
|
|
117
|
-
} else if (this.level === 'year-quarter') {
|
|
118
|
-
ticks = d3.timeMonth.every(3)!.range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 3))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
addGridLines(ticks!)
|
|
122
|
-
|
|
123
|
-
this.renderResourceAllocations(body, ticks!, chartHeight)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
renderResourceAllocations(
|
|
128
|
-
body: d3.Selection<SVGElement, unknown, null, undefined>,
|
|
129
|
-
ticks: Date[],
|
|
130
|
-
chartHeight: number
|
|
131
|
-
) {
|
|
132
|
-
const resourceAllocations = this.calculateResourceAllocations(ticks)
|
|
133
|
-
|
|
134
|
-
this.resources.forEach((resource, index) => {
|
|
135
|
-
const y = index * 30 + 15 // Center the text vertically in the row
|
|
136
|
-
ticks.forEach(tick => {
|
|
137
|
-
const tickEnd = this.getTickEnd(tick)
|
|
138
|
-
const dateKey = this.formatDateKey(tick, tickEnd)
|
|
139
|
-
const allocation = resourceAllocations[resource.type][dateKey]
|
|
140
|
-
if (allocation > 0) {
|
|
141
|
-
const startX = this.timeScale(tick)
|
|
142
|
-
const tickInterval = this.timeScale(tickEnd) - startX
|
|
143
|
-
|
|
144
|
-
body
|
|
145
|
-
.append('text')
|
|
146
|
-
.attr('x', startX + tickInterval / 2)
|
|
147
|
-
.attr('y', y)
|
|
148
|
-
.attr('text-anchor', 'middle')
|
|
149
|
-
.attr('alignment-baseline', 'middle')
|
|
150
|
-
.attr('dominant-baseline', 'middle')
|
|
151
|
-
.attr('stroke', 'var(--ox-gantt-color-text, var(--md-sys-color-on-primary-container))')
|
|
152
|
-
.text(allocation)
|
|
153
|
-
.style('font-size', '12px')
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
// Draw horizontal grid lines for each resource row
|
|
159
|
-
for (let i = 0; i <= this.resources.length; i++) {
|
|
160
|
-
body
|
|
161
|
-
.append('line')
|
|
162
|
-
.attr('x1', 0)
|
|
163
|
-
.attr('x2', this.getChartWidth())
|
|
164
|
-
.attr('y1', i * 30)
|
|
165
|
-
.attr('y2', i * 30)
|
|
166
|
-
.attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
|
|
167
|
-
.attr('stroke-width', 1)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
calculateResourceAllocations(ticks: Date[]): { [key: string]: { [key: string]: number } } {
|
|
172
|
-
const resourceAllocations: { [key: string]: { [key: string]: number } } = {}
|
|
173
|
-
|
|
174
|
-
this.resources.forEach(resource => {
|
|
175
|
-
resourceAllocations[resource.type] = {}
|
|
176
|
-
ticks.forEach(tick => {
|
|
177
|
-
const tickEnd = this.getTickEnd(tick)
|
|
178
|
-
const dateKey = this.formatDateKey(tick, tickEnd)
|
|
179
|
-
resourceAllocations[resource.type][dateKey] = 0
|
|
180
|
-
})
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
this.tasks.forEach(task => {
|
|
184
|
-
const startDate = new Date(task.startDate)
|
|
185
|
-
const endDate = new Date(task.endDate)
|
|
186
|
-
let currentDate = startDate
|
|
187
|
-
|
|
188
|
-
while (currentDate <= endDate) {
|
|
189
|
-
const tick = ticks.find(t => currentDate >= t && currentDate < this.getTickEnd(t))
|
|
190
|
-
if (tick) {
|
|
191
|
-
const tickEnd = this.getTickEnd(tick)
|
|
192
|
-
const dateKey = this.formatDateKey(tick, tickEnd)
|
|
193
|
-
|
|
194
|
-
;(task.resources || []).forEach(resource => {
|
|
195
|
-
if (resourceAllocations[resource.type][dateKey] !== undefined) {
|
|
196
|
-
resourceAllocations[resource.type][dateKey] += resource.allocated
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
currentDate.setDate(currentDate.getDate() + 1)
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
return resourceAllocations
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
getTickEnd(tick: Date): Date {
|
|
209
|
-
if (this.level === 'week-day') {
|
|
210
|
-
return d3.timeDay.offset(tick, 1)
|
|
211
|
-
} else if (this.level === 'quarter-week') {
|
|
212
|
-
return d3.timeWeek.offset(tick, 1)
|
|
213
|
-
} else if (this.level === 'year-month') {
|
|
214
|
-
return d3.timeMonth.offset(tick, 1)
|
|
215
|
-
} else if (this.level === 'year-quarter') {
|
|
216
|
-
return d3.timeMonth.offset(tick, 3)
|
|
217
|
-
}
|
|
218
|
-
return d3.timeDay.offset(tick, 1)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
formatDateKey(start: Date, end: Date): string {
|
|
222
|
-
return `${start.toISOString().split('T')[0]}_${end.toISOString().split('T')[0]}`
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
handleWheelForBody(event: WheelEvent, container: HTMLDivElement) {
|
|
226
|
-
event.preventDefault()
|
|
227
|
-
event.stopPropagation()
|
|
228
|
-
|
|
229
|
-
const deltaModeFactor =
|
|
230
|
-
event.deltaMode === WheelEvent.DOM_DELTA_LINE
|
|
231
|
-
? 16
|
|
232
|
-
: event.deltaMode === WheelEvent.DOM_DELTA_PAGE
|
|
233
|
-
? container.clientHeight
|
|
234
|
-
: 1
|
|
235
|
-
const deltaX = event.deltaX * deltaModeFactor
|
|
236
|
-
const deltaY = event.deltaY * deltaModeFactor
|
|
237
|
-
|
|
238
|
-
container.scrollLeft += deltaX
|
|
239
|
-
container.scrollTop += deltaY
|
|
240
|
-
|
|
241
|
-
const customEvent = new CustomEvent('scroll', {
|
|
242
|
-
detail: {
|
|
243
|
-
scrollLeft: container.scrollLeft,
|
|
244
|
-
scrollTop: container.scrollTop
|
|
245
|
-
},
|
|
246
|
-
bubbles: true,
|
|
247
|
-
composed: true
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
this.host.dispatchEvent(customEvent)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement) {
|
|
254
|
-
event.stopPropagation()
|
|
255
|
-
|
|
256
|
-
this.touchStartX = event.touches[0].clientX
|
|
257
|
-
this.touchStartY = event.touches[0].clientY
|
|
258
|
-
|
|
259
|
-
this.scrollStartX = container.scrollLeft
|
|
260
|
-
this.scrollStartY = container.scrollTop
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement) {
|
|
264
|
-
const touchCurrentX = event.touches[0].clientX
|
|
265
|
-
const touchCurrentY = event.touches[0].clientY
|
|
266
|
-
|
|
267
|
-
const deltaX = this.touchStartX! - touchCurrentX
|
|
268
|
-
const deltaY = this.touchStartY! - touchCurrentY
|
|
269
|
-
|
|
270
|
-
container.scrollLeft = this.scrollStartX! + deltaX
|
|
271
|
-
container.scrollTop = this.scrollStartY! + deltaY
|
|
272
|
-
|
|
273
|
-
const customEvent = new CustomEvent('scroll', {
|
|
274
|
-
detail: {
|
|
275
|
-
scrollLeft: container.scrollLeft,
|
|
276
|
-
scrollTop: container.scrollTop
|
|
277
|
-
},
|
|
278
|
-
bubbles: true,
|
|
279
|
-
composed: true
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
this.host.dispatchEvent(customEvent)
|
|
283
|
-
}
|
|
284
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export type TaskTag = 'done' | 'active' | 'critical' | 'milestone'
|
|
2
|
-
export type TaskType = 'group' | 'task' | 'milestone' | 'phase'
|
|
3
|
-
|
|
4
|
-
export interface Task {
|
|
5
|
-
id: string
|
|
6
|
-
title: string
|
|
7
|
-
type: TaskType
|
|
8
|
-
startDate: Date | string
|
|
9
|
-
endDate: Date | string
|
|
10
|
-
progress?: number
|
|
11
|
-
dependsOn?: string
|
|
12
|
-
duration: number
|
|
13
|
-
tags?: TaskTag[]
|
|
14
|
-
children?: Task[]
|
|
15
|
-
resources?: Resource[]
|
|
16
|
-
collapsed?: boolean
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface ColumnConfig {
|
|
20
|
-
name: string
|
|
21
|
-
label: string
|
|
22
|
-
visible: boolean
|
|
23
|
-
width: number
|
|
24
|
-
order: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type TimeScale = 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'
|
|
28
|
-
|
|
29
|
-
export interface Resource {
|
|
30
|
-
type: string
|
|
31
|
-
allocated: number
|
|
32
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { TimeScale } from './types'
|
|
2
|
-
|
|
3
|
-
const levels: TimeScale[] = ['week-day', 'quarter-week', 'year-month', 'year-quarter']
|
|
4
|
-
|
|
5
|
-
export function levelUp(level: 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'): TimeScale {
|
|
6
|
-
const current = Math.min(levels.length, levels.indexOf(level) + 1)
|
|
7
|
-
return levels[current]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function levelDown(level: 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'): TimeScale {
|
|
11
|
-
const current = Math.max(0, levels.indexOf(level) - 1)
|
|
12
|
-
return levels[current]
|
|
13
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { html, TemplateResult } from 'lit'
|
|
2
|
-
import { CommonHeaderStyles } from '@operato/styles'
|
|
3
|
-
import '../src/ox-gantt-chart.js'
|
|
4
|
-
|
|
5
|
-
import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
title: 'ox-gantt-chart',
|
|
9
|
-
component: 'ox-gantt-chart',
|
|
10
|
-
argTypes: {
|
|
11
|
-
axisScale: { control: 'select', options: ['year-quarter', 'year-month', 'quarter-week', 'week-day'] },
|
|
12
|
-
fromDate: { control: 'string' },
|
|
13
|
-
toDate: { control: 'string' },
|
|
14
|
-
extendGridLines: { control: 'boolean' }
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface Story<T> {
|
|
19
|
-
(args: T): TemplateResult
|
|
20
|
-
args?: Partial<T>
|
|
21
|
-
argTypes?: Record<string, unknown>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface ArgTypes {
|
|
25
|
-
axisScale: 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'
|
|
26
|
-
fromDate: string
|
|
27
|
-
toDate: string
|
|
28
|
-
extendGridLines: boolean
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const Template: Story<ArgTypes> = ({
|
|
32
|
-
axisScale = 'week-day',
|
|
33
|
-
fromDate = '',
|
|
34
|
-
toDate = '',
|
|
35
|
-
extendGridLines
|
|
36
|
-
}: ArgTypes) => html`
|
|
37
|
-
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" />
|
|
38
|
-
|
|
39
|
-
<link href="/themes/light.css" rel="stylesheet" />
|
|
40
|
-
<link href="/themes/dark.css" rel="stylesheet" />
|
|
41
|
-
<link href="/themes/spacing.css" rel="stylesheet" />
|
|
42
|
-
<link href="/themes/md-typescale-styles.css" rel="stylesheet" />
|
|
43
|
-
|
|
44
|
-
<link
|
|
45
|
-
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
|
|
46
|
-
rel="stylesheet"
|
|
47
|
-
/>
|
|
48
|
-
<link
|
|
49
|
-
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
|
|
50
|
-
rel="stylesheet"
|
|
51
|
-
/>
|
|
52
|
-
<link
|
|
53
|
-
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
|
|
54
|
-
rel="stylesheet"
|
|
55
|
-
/>
|
|
56
|
-
|
|
57
|
-
<style>
|
|
58
|
-
${MDTypeScaleStyles.cssText}
|
|
59
|
-
</style>
|
|
60
|
-
|
|
61
|
-
<style>
|
|
62
|
-
${CommonHeaderStyles.cssText}
|
|
63
|
-
</style>
|
|
64
|
-
|
|
65
|
-
<style>
|
|
66
|
-
body {
|
|
67
|
-
width: 100%;
|
|
68
|
-
height: 800px;
|
|
69
|
-
text-align: center;
|
|
70
|
-
|
|
71
|
-
background-color: var(--md-sys-color-background);
|
|
72
|
-
color: var(--md-sys-color-on-background);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
ox-gantt {
|
|
76
|
-
width: 90%;
|
|
77
|
-
height: 500px;
|
|
78
|
-
box-sizing: border-box;
|
|
79
|
-
|
|
80
|
-
background-color: var(--md-sys-color-primary-container);
|
|
81
|
-
color: var(--md-sys-color-on-primary-container);
|
|
82
|
-
}
|
|
83
|
-
</style>
|
|
84
|
-
|
|
85
|
-
<style>
|
|
86
|
-
ox-gantt-chart {
|
|
87
|
-
height: 500px;
|
|
88
|
-
border: 1px solid black;
|
|
89
|
-
}
|
|
90
|
-
</style>
|
|
91
|
-
|
|
92
|
-
<ox-gantt-chart
|
|
93
|
-
.axisScale=${axisScale}
|
|
94
|
-
.fromDate=${fromDate}
|
|
95
|
-
.toDate=${toDate}
|
|
96
|
-
?extend-grid-lines=${extendGridLines}
|
|
97
|
-
></ox-gantt-chart>
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
export const YearMonth = Template.bind({})
|
|
101
|
-
YearMonth.args = {
|
|
102
|
-
axisScale: 'year-quarter',
|
|
103
|
-
fromDate: '2020-01-01',
|
|
104
|
-
toDate: '2025-12-31'
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
YearMonth.args = {
|
|
108
|
-
axisScale: 'year-month',
|
|
109
|
-
fromDate: '2022-01-01',
|
|
110
|
-
toDate: '2024-12-31'
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const MonthWeek = Template.bind({})
|
|
114
|
-
MonthWeek.args = {
|
|
115
|
-
axisScale: 'quarter-week',
|
|
116
|
-
fromDate: '2022-01-01',
|
|
117
|
-
toDate: '2023-03-31'
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export const WeekDay = Template.bind({})
|
|
121
|
-
WeekDay.args = {
|
|
122
|
-
axisScale: 'week-day',
|
|
123
|
-
fromDate: '2022-01-01',
|
|
124
|
-
toDate: '2022-11-15'
|
|
125
|
-
}
|