@operato/gantt 7.0.60 → 7.0.69

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.
@@ -1,21 +1,12 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement, html, css } from 'lit';
3
3
  import { customElement, property, query } from 'lit/decorators.js';
4
- import * as d3 from 'd3';
4
+ import { ResourceChartController } from './resource-chart-controller';
5
+ import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles';
5
6
  import { ScrollbarStyles } from '@operato/styles';
6
- import { drawTimeScaleHeader } from './draw-time-scale-header';
7
7
  let OxResourceChart = class OxResourceChart extends LitElement {
8
- constructor() {
9
- super(...arguments);
10
- this.fromDate = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0];
11
- this.toDate = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0];
12
- this.axisScale = 'week-day';
13
- this.resources = [];
14
- this.tasks = [];
15
- this.baseWidth = 30;
16
- this.level = 'week-day';
17
- }
18
8
  static { this.styles = [
9
+ MDTypeScaleStyles,
19
10
  ScrollbarStyles,
20
11
  css `
21
12
  :host {
@@ -25,18 +16,16 @@ let OxResourceChart = class OxResourceChart extends LitElement {
25
16
  }
26
17
 
27
18
  div[chart-container] {
28
- display: flex;
29
19
  flex-direction: column;
30
-
31
20
  overflow-x: auto;
32
- overflow-y: auto;
21
+ overflow-y: hidden;
33
22
  }
34
23
 
35
24
  svg[header] {
36
25
  display: block;
37
26
  min-width: 100%;
38
27
  box-sizing: border-box;
39
- border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-on-secondary-container));
28
+ border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-outline));
40
29
  height: 30px;
41
30
  background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));
42
31
  color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
@@ -46,16 +35,10 @@ let OxResourceChart = class OxResourceChart extends LitElement {
46
35
  }
47
36
 
48
37
  svg[body] {
49
- flex: 1;
50
38
  display: block;
51
39
  min-width: 100%;
52
40
  }
53
41
 
54
- .top-axis text,
55
- .bottom-axis text {
56
- font-size: 12px;
57
- }
58
-
59
42
  .grid line {
60
43
  stroke: #e0e0e0;
61
44
  }
@@ -63,227 +46,72 @@ let OxResourceChart = class OxResourceChart extends LitElement {
63
46
  .grid path {
64
47
  stroke-width: 0;
65
48
  }
66
-
67
- .no-select {
68
- user-select: none;
69
- }
70
-
71
- .selected {
72
- stroke-width: 2px;
73
- stroke: var(--ox-gantt-selected-color, blue);
74
- }
75
49
  `
76
50
  ]; }
77
- render() {
78
- return html `
79
- <div chart-container>
80
- <svg header></svg>
81
- <svg body></svg>
82
- </div>
83
- `;
51
+ constructor() {
52
+ super();
53
+ this.fromDate = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0];
54
+ this.toDate = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0];
55
+ this.axisScale = 'week-day';
56
+ this.resources = [];
57
+ this.tasks = [];
58
+ this.resourceChartController = new ResourceChartController(this, this.fromDate, this.toDate, this.axisScale);
84
59
  }
85
60
  updated(changedProperties) {
86
- if (changedProperties.has('fromDate') || changedProperties.has('toDate') || changedProperties.has('axisScale')) {
87
- this.updateTimeScale();
88
- }
89
- if (changedProperties.has('resources') || changedProperties.has('tasks')) {
90
- this.drawBody();
91
- }
92
- this.drawAxes();
93
- }
94
- updateTimeScale() {
95
- this.fromTime = new Date(this.fromDate);
96
- this.toTime = new Date(this.toDate);
97
- this.timeScale = d3
98
- .scaleTime()
99
- .domain([d3.timeDay.floor(new Date(this.fromDate)), d3.timeDay.offset(new Date(this.toDate), 1)])
100
- .range([0, this.getChartWidth()]);
101
- }
102
- getChartWidth() {
103
- const totalDays = d3.timeDay.count(new Date(this.fromDate), d3.timeDay.offset(new Date(this.toDate), 1));
104
- return (totalDays * this.baseWidth) / this.getScale();
105
- }
106
- getScale() {
107
- if (this.level == 'quarter-week') {
108
- return 7 / 2;
61
+ if (changedProperties.has('fromDate') || changedProperties.has('toDate')) {
62
+ this.resourceChartController.updateRange(this.fromDate, this.toDate);
109
63
  }
110
- else if (this.level == 'year-month') {
111
- return 30 / 2;
64
+ if (changedProperties.has('resources')) {
65
+ this.resourceChartController.setResources(this.resources);
66
+ this.updateChartHeight(); // 리소스의 수에 따라 차트의 높이를 업데이트합니다.
112
67
  }
113
- else if (this.level === 'year-quarter') {
114
- return 90 / 2;
68
+ if (changedProperties.has('tasks')) {
69
+ this.resourceChartController.setTasks(this.tasks);
70
+ this.updateChartHeight(); // 리소스의 수에 따라 차트의 높이를 업데이트합니다.
115
71
  }
116
- return 1;
117
- }
118
- drawAxes() {
119
- drawTimeScaleHeader(this.svgHeader, this.timeScale, this.fromTime, this.toTime, this.baseWidth, this.level, false /* 1 level only header */);
120
- }
121
- drawBody() {
122
- const body = d3.select(this.svgBody);
123
- body.selectAll('*').remove();
124
- body.attr('width', this.getChartWidth());
125
- if (this.resources.length > 0) {
126
- const chartHeight = this.resources.length * 30;
127
- const addVerticalGridLines = (ticks) => {
128
- ticks.forEach(tick => {
129
- const startX = this.timeScale(tick);
130
- body
131
- .append('line')
132
- .attr('x1', startX)
133
- .attr('x2', startX)
134
- .attr('y1', 0)
135
- .attr('y2', chartHeight) // Ensure vertical lines extend to the bottom
136
- .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
137
- .attr('stroke-width', 1);
138
- });
139
- };
140
- const addHorizontalGridLines = () => {
141
- this.resources.forEach((_, index) => {
142
- const y = (index + 1) * 30;
143
- body
144
- .append('line')
145
- .attr('x1', 0)
146
- .attr('x2', this.getChartWidth())
147
- .attr('y1', y)
148
- .attr('y2', y)
149
- .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
150
- .attr('stroke-width', 1);
151
- });
152
- // Ensure the last horizontal line extends to the bottom of the chart
153
- body
154
- .append('line')
155
- .attr('x1', 0)
156
- .attr('x2', this.getChartWidth())
157
- .attr('y1', chartHeight)
158
- .attr('y2', chartHeight)
159
- .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
160
- .attr('stroke-width', 1);
161
- };
162
- let ticks;
163
- if (this.level === 'week-day') {
164
- ticks = d3.timeDay
165
- .every(1)
166
- .range(d3.timeDay.floor(new Date(this.fromDate)), d3.timeDay.offset(new Date(this.toDate), 1));
167
- }
168
- else if (this.level === 'quarter-week') {
169
- ticks = d3.timeWeek
170
- .every(1)
171
- .range(d3.timeWeek.floor(new Date(this.fromDate)), d3.timeWeek.offset(new Date(this.toDate), 1));
172
- }
173
- else if (this.level === 'year-month') {
174
- ticks = d3.timeMonth
175
- .every(1)
176
- .range(d3.timeMonth.floor(new Date(this.fromDate)), d3.timeMonth.offset(new Date(this.toDate), 1));
177
- }
178
- else if (this.level === 'year-quarter') {
179
- ticks = d3.timeMonth
180
- .every(3)
181
- .range(d3.timeMonth.floor(new Date(this.fromDate)), d3.timeMonth.offset(new Date(this.toDate), 3));
182
- }
183
- addVerticalGridLines(ticks);
184
- addHorizontalGridLines();
185
- // Render the resource allocations
186
- this.renderResourceAllocations(body, ticks);
72
+ if (changedProperties.has('axisScale')) {
73
+ this.resourceChartController.level = this.axisScale;
74
+ this.resourceChartController.updateTimeScale();
187
75
  }
76
+ // 차트 렌더링
77
+ this.resourceChartController.drawAxes(this.svgHeader);
78
+ this.resourceChartController.drawBody(this.svgBody);
188
79
  }
189
- renderResourceAllocations(body, ticks) {
190
- const resourceAllocations = this.calculateResourceAllocations(ticks);
191
- this.resources.forEach((resource, index) => {
192
- const y = index * 30 + 15; // Center the text vertically in the row
193
- ticks.forEach(tick => {
194
- const tickEnd = this.getTickEnd(tick);
195
- const dateKey = this.formatDateKey(tick, tickEnd);
196
- const allocation = resourceAllocations[resource.type][dateKey];
197
- if (allocation > 0) {
198
- const startX = this.timeScale(tick);
199
- const tickInterval = this.timeScale(tickEnd) - startX;
200
- body
201
- .append('text')
202
- .attr('x', startX + tickInterval / 2)
203
- .attr('y', y)
204
- .attr('text-anchor', 'middle')
205
- .attr('alignment-baseline', 'middle')
206
- .attr('dominant-baseline', 'middle')
207
- .text(allocation)
208
- .style('font-size', '12px');
209
- }
210
- });
211
- });
80
+ updateChartHeight() {
81
+ const resourceCount = this.resources.length;
82
+ const rowHeight = 30; // 리소스 하나당 할당된 높이 (픽셀)
83
+ const minHeight = 200; // 최소 높이
84
+ const chartHeight = Math.max(resourceCount * rowHeight, minHeight);
85
+ this.svgBody.style.height = `${chartHeight}px`;
212
86
  }
213
- calculateResourceAllocations(ticks) {
214
- const resourceAllocations = {};
215
- // Initialize the resourceAllocations object
216
- this.resources.forEach(resource => {
217
- resourceAllocations[resource.type] = {};
218
- ticks.forEach(tick => {
219
- const tickEnd = this.getTickEnd(tick);
220
- const dateKey = this.formatDateKey(tick, tickEnd);
221
- resourceAllocations[resource.type][dateKey] = 0;
222
- });
223
- });
224
- // Function to process tasks recursively
225
- const processTask = (task) => {
226
- const startDate = new Date(task.startDate);
227
- const endDate = new Date(task.endDate);
228
- let currentDate = startDate;
229
- while (currentDate <= endDate) {
230
- const tick = ticks.find(t => currentDate >= t && currentDate < this.getTickEnd(t));
231
- if (tick) {
232
- const tickEnd = this.getTickEnd(tick);
233
- const dateKey = this.formatDateKey(tick, tickEnd);
234
- (task.resources || []).forEach(resource => {
235
- if (resourceAllocations[resource.type][dateKey] !== undefined) {
236
- resourceAllocations[resource.type][dateKey] += resource.allocated;
237
- }
238
- });
239
- }
240
- currentDate.setDate(currentDate.getDate() + 1);
241
- }
242
- // Recursively process child tasks
243
- if (task.children) {
244
- task.children.forEach(childTask => processTask(childTask));
245
- }
246
- };
247
- // Process all tasks
248
- this.tasks.forEach(task => processTask(task));
249
- return resourceAllocations;
250
- }
251
- getTickEnd(tick) {
252
- if (this.level === 'week-day') {
253
- return d3.timeDay.offset(tick, 1);
254
- }
255
- else if (this.level === 'quarter-week') {
256
- return d3.timeWeek.offset(tick, 1);
257
- }
258
- else if (this.level === 'year-month') {
259
- return d3.timeMonth.offset(tick, 1);
260
- }
261
- else if (this.level === 'year-quarter') {
262
- return d3.timeMonth.offset(tick, 3);
263
- }
264
- return d3.timeDay.offset(tick, 1);
265
- }
266
- formatDateKey(start, end) {
267
- return `${start.toISOString().split('T')[0]}_${end.toISOString().split('T')[0]}`;
87
+ render() {
88
+ return html `
89
+ <div
90
+ chart-container
91
+ @wheel=${(e) => this.resourceChartController.handleWheelForBody(e, this.container)}
92
+ @touchstart=${(e) => this.resourceChartController.handleTouchStartForBody(e, this.container)}
93
+ @touchmove=${(e) => this.resourceChartController.handleTouchMoveForBody(e, this.container)}
94
+ >
95
+ <svg header></svg>
96
+ <svg body></svg>
97
+ </div>
98
+ `;
268
99
  }
269
100
  syncTimeScale(detail) {
270
- this.baseWidth = detail.baseWidth;
271
- this.level = detail.level;
272
- this.updateTimeScale();
273
- this.drawAxes();
274
- this.drawBody();
275
- }
276
- setVerticalOffset(offset) {
277
- this.container.scrollTop = offset;
101
+ this.resourceChartController.syncTimeScale(detail);
102
+ this.requestUpdate();
278
103
  }
279
- getVerticalOffset() {
280
- return this.container.scrollTop;
104
+ getHorizontalOffset() {
105
+ return this.container.scrollLeft;
281
106
  }
282
107
  setHorizontalOffset(offset) {
283
108
  this.container.scrollLeft = offset;
284
109
  }
285
- getHorizontalOffset() {
286
- return this.container.scrollLeft;
110
+ getVerticalOffset() {
111
+ return this.container.scrollTop;
112
+ }
113
+ setVerticalOffset(offset) {
114
+ this.container.scrollTop = offset;
287
115
  }
288
116
  };
289
117
  __decorate([
@@ -302,7 +130,7 @@ __decorate([
302
130
  property({ type: Array })
303
131
  ], OxResourceChart.prototype, "tasks", void 0);
304
132
  __decorate([
305
- query('[chart-container')
133
+ query('[chart-container]')
306
134
  ], OxResourceChart.prototype, "container", void 0);
307
135
  __decorate([
308
136
  query('svg[header]')
@@ -1 +1 @@
1
- {"version":3,"file":"ox-resource-chart.js","sourceRoot":"","sources":["../../src/ox-resource-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport * as d3 from 'd3'\n\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { drawTimeScaleHeader } from './draw-time-scale-header'\nimport { Task, TimeScale } from './types'\n\n@customElement('ox-resource-chart')\nexport class OxResourceChart extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n overflow: hidden;\n position: relative;\n }\n\n div[chart-container] {\n display: flex;\n flex-direction: column;\n\n overflow-x: auto;\n overflow-y: auto;\n }\n\n svg[header] {\n display: block;\n min-width: 100%;\n box-sizing: border-box;\n border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-on-secondary-container));\n height: 30px;\n background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));\n color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n svg[body] {\n flex: 1;\n display: block;\n min-width: 100%;\n }\n\n .top-axis text,\n .bottom-axis text {\n font-size: 12px;\n }\n\n .grid line {\n stroke: #e0e0e0;\n }\n\n .grid path {\n stroke-width: 0;\n }\n\n .no-select {\n user-select: none;\n }\n\n .selected {\n stroke-width: 2px;\n stroke: var(--ox-gantt-selected-color, blue);\n }\n `\n ]\n\n @property({ type: String }) fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0]\n @property({ type: String }) toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0]\n @property({ type: String }) axisScale: string = 'week-day'\n @property({ type: Array }) resources: any[] = []\n @property({ type: Array }) tasks: Task[] = []\n\n private timeScale: any\n private baseWidth: number = 30\n private level: TimeScale = 'week-day'\n private fromTime?: Date\n private toTime?: Date\n\n @query('[chart-container') container!: HTMLDivElement\n @query('svg[header]') svgHeader!: SVGSVGElement\n @query('svg[body]') svgBody!: SVGSVGElement\n\n render() {\n return html`\n <div chart-container>\n <svg header></svg>\n <svg body></svg>\n </div>\n `\n }\n\n updated(changedProperties: PropertyValues<this>) {\n if (changedProperties.has('fromDate') || changedProperties.has('toDate') || changedProperties.has('axisScale')) {\n this.updateTimeScale()\n }\n\n if (changedProperties.has('resources') || changedProperties.has('tasks')) {\n this.drawBody()\n }\n\n this.drawAxes()\n }\n\n updateTimeScale() {\n this.fromTime = new Date(this.fromDate)\n this.toTime = new Date(this.toDate)\n\n this.timeScale = d3\n .scaleTime()\n .domain([d3.timeDay.floor(new Date(this.fromDate)), d3.timeDay.offset(new Date(this.toDate), 1)])\n .range([0, this.getChartWidth()])\n }\n\n getChartWidth() {\n const totalDays = d3.timeDay.count(new Date(this.fromDate), d3.timeDay.offset(new Date(this.toDate), 1))\n return (totalDays * this.baseWidth) / this.getScale()\n }\n\n getScale() {\n if (this.level == 'quarter-week') {\n return 7 / 2\n } else if (this.level == 'year-month') {\n return 30 / 2\n } else if (this.level === 'year-quarter') {\n return 90 / 2\n }\n return 1\n }\n\n drawAxes() {\n drawTimeScaleHeader(\n this.svgHeader as any,\n this.timeScale,\n this.fromTime!,\n this.toTime!,\n this.baseWidth,\n this.level,\n false /* 1 level only header */\n )\n }\n\n drawBody() {\n const body = d3.select(this.svgBody)\n\n body.selectAll('*').remove()\n body.attr('width', this.getChartWidth())\n\n if (this.resources.length > 0) {\n const chartHeight = this.resources.length * 30\n\n const addVerticalGridLines = (ticks: Date[]) => {\n ticks.forEach(tick => {\n const startX = this.timeScale(tick)\n body\n .append('line')\n .attr('x1', startX)\n .attr('x2', startX)\n .attr('y1', 0)\n .attr('y2', chartHeight) // Ensure vertical lines extend to the bottom\n .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')\n .attr('stroke-width', 1)\n })\n }\n\n const addHorizontalGridLines = () => {\n this.resources.forEach((_, index) => {\n const y = (index + 1) * 30\n body\n .append('line')\n .attr('x1', 0)\n .attr('x2', this.getChartWidth())\n .attr('y1', y)\n .attr('y2', y)\n .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')\n .attr('stroke-width', 1)\n })\n\n // Ensure the last horizontal line extends to the bottom of the chart\n body\n .append('line')\n .attr('x1', 0)\n .attr('x2', this.getChartWidth())\n .attr('y1', chartHeight)\n .attr('y2', chartHeight)\n .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')\n .attr('stroke-width', 1)\n }\n\n let ticks\n if (this.level === 'week-day') {\n ticks = d3.timeDay\n .every(1)!\n .range(d3.timeDay.floor(new Date(this.fromDate)), d3.timeDay.offset(new Date(this.toDate), 1))\n } else if (this.level === 'quarter-week') {\n ticks = d3.timeWeek\n .every(1)!\n .range(d3.timeWeek.floor(new Date(this.fromDate)), d3.timeWeek.offset(new Date(this.toDate), 1))\n } else if (this.level === 'year-month') {\n ticks = d3.timeMonth\n .every(1)!\n .range(d3.timeMonth.floor(new Date(this.fromDate)), d3.timeMonth.offset(new Date(this.toDate), 1))\n } else if (this.level === 'year-quarter') {\n ticks = d3.timeMonth\n .every(3)!\n .range(d3.timeMonth.floor(new Date(this.fromDate)), d3.timeMonth.offset(new Date(this.toDate), 3))\n }\n\n addVerticalGridLines(ticks!)\n addHorizontalGridLines()\n\n // Render the resource allocations\n this.renderResourceAllocations(body, ticks!)\n }\n }\n\n renderResourceAllocations(body: d3.Selection<SVGSVGElement, unknown, null, undefined>, ticks: Date[]) {\n const resourceAllocations = this.calculateResourceAllocations(ticks)\n\n this.resources.forEach((resource, index) => {\n const y = index * 30 + 15 // Center the text vertically in the row\n ticks.forEach(tick => {\n const tickEnd = this.getTickEnd(tick)\n const dateKey = this.formatDateKey(tick, tickEnd)\n const allocation = resourceAllocations[resource.type][dateKey]\n if (allocation > 0) {\n const startX = this.timeScale(tick)\n const tickInterval = this.timeScale(tickEnd) - startX\n\n body\n .append('text')\n .attr('x', startX + tickInterval / 2)\n .attr('y', y)\n .attr('text-anchor', 'middle')\n .attr('alignment-baseline', 'middle')\n .attr('dominant-baseline', 'middle')\n .text(allocation)\n .style('font-size', '12px')\n }\n })\n })\n }\n\n calculateResourceAllocations(ticks: Date[]) {\n const resourceAllocations: { [key: string]: { [key: string]: number } } = {}\n\n // Initialize the resourceAllocations object\n this.resources.forEach(resource => {\n resourceAllocations[resource.type] = {}\n ticks.forEach(tick => {\n const tickEnd = this.getTickEnd(tick)\n const dateKey = this.formatDateKey(tick, tickEnd)\n resourceAllocations[resource.type][dateKey] = 0\n })\n })\n\n // Function to process tasks recursively\n const processTask = (task: Task) => {\n const startDate = new Date(task.startDate)\n const endDate = new Date(task.endDate)\n let currentDate = startDate\n\n while (currentDate <= endDate) {\n const tick = ticks.find(t => currentDate >= t && currentDate < this.getTickEnd(t))\n if (tick) {\n const tickEnd = this.getTickEnd(tick)\n const dateKey = this.formatDateKey(tick, tickEnd)\n\n ;(task.resources || []).forEach(resource => {\n if (resourceAllocations[resource.type][dateKey] !== undefined) {\n resourceAllocations[resource.type][dateKey] += resource.allocated\n }\n })\n }\n\n currentDate.setDate(currentDate.getDate() + 1)\n }\n\n // Recursively process child tasks\n if (task.children) {\n task.children.forEach(childTask => processTask(childTask))\n }\n }\n\n // Process all tasks\n this.tasks.forEach(task => processTask(task))\n\n return resourceAllocations\n }\n\n getTickEnd(tick: Date) {\n if (this.level === 'week-day') {\n return d3.timeDay.offset(tick, 1)\n } else if (this.level === 'quarter-week') {\n return d3.timeWeek.offset(tick, 1)\n } else if (this.level === 'year-month') {\n return d3.timeMonth.offset(tick, 1)\n } else if (this.level === 'year-quarter') {\n return d3.timeMonth.offset(tick, 3)\n }\n return d3.timeDay.offset(tick, 1)\n }\n\n formatDateKey(start: Date, end: Date) {\n return `${start.toISOString().split('T')[0]}_${end.toISOString().split('T')[0]}`\n }\n\n syncTimeScale(detail: { baseWidth: number; level: TimeScale }) {\n this.baseWidth = detail.baseWidth\n this.level = detail.level\n\n this.updateTimeScale()\n this.drawAxes()\n this.drawBody()\n }\n\n setVerticalOffset(offset: number) {\n this.container.scrollTop = offset\n }\n\n getVerticalOffset(): number {\n return this.container.scrollTop\n }\n\n setHorizontalOffset(offset: number) {\n this.container.scrollLeft = offset\n }\n\n getHorizontalOffset(): number {\n return this.container.scrollLeft\n }\n}\n"]}
1
+ {"version":3,"file":"ox-resource-chart.js","sourceRoot":"","sources":["../../src/ox-resource-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ResourceChartController } from './resource-chart-controller'\nimport { Task, Resource, TimeScale } from './types'\n\nimport { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'\nimport { ScrollbarStyles } from '@operato/styles'\n\n@customElement('ox-resource-chart')\nexport class OxResourceChart extends LitElement {\n static styles = [\n MDTypeScaleStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n overflow: hidden;\n position: relative;\n }\n\n div[chart-container] {\n flex-direction: column;\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n svg[header] {\n display: block;\n min-width: 100%;\n box-sizing: border-box;\n border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-outline));\n height: 30px;\n background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));\n color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n svg[body] {\n display: block;\n min-width: 100%;\n }\n\n .grid line {\n stroke: #e0e0e0;\n }\n\n .grid path {\n stroke-width: 0;\n }\n `\n ]\n\n @property({ type: String }) fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0]\n @property({ type: String }) toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0]\n @property({ type: String }) axisScale: TimeScale = 'week-day'\n @property({ type: Array }) resources: Resource[] = []\n @property({ type: Array }) tasks: Task[] = []\n\n @query('[chart-container]') container!: HTMLDivElement\n @query('svg[header]') svgHeader!: SVGSVGElement\n @query('svg[body]') svgBody!: SVGSVGElement\n\n private resourceChartController: ResourceChartController\n\n constructor() {\n super()\n this.resourceChartController = new ResourceChartController(this, this.fromDate, this.toDate, this.axisScale)\n }\n\n updated(changedProperties: Map<string | number | symbol, unknown>) {\n if (changedProperties.has('fromDate') || changedProperties.has('toDate')) {\n this.resourceChartController.updateRange(this.fromDate, this.toDate)\n }\n\n if (changedProperties.has('resources')) {\n this.resourceChartController.setResources(this.resources)\n this.updateChartHeight() // 리소스의 수에 따라 차트의 높이를 업데이트합니다.\n }\n\n if (changedProperties.has('tasks')) {\n this.resourceChartController.setTasks(this.tasks)\n this.updateChartHeight() // 리소스의 수에 따라 차트의 높이를 업데이트합니다.\n }\n\n if (changedProperties.has('axisScale')) {\n this.resourceChartController.level = this.axisScale\n this.resourceChartController.updateTimeScale()\n }\n\n // 차트 렌더링\n this.resourceChartController.drawAxes(this.svgHeader)\n this.resourceChartController.drawBody(this.svgBody)\n }\n\n updateChartHeight() {\n const resourceCount = this.resources.length\n const rowHeight = 30 // 리소스 하나당 할당된 높이 (픽셀)\n const minHeight = 200 // 최소 높이\n const chartHeight = Math.max(resourceCount * rowHeight, minHeight)\n\n this.svgBody.style.height = `${chartHeight}px`\n }\n\n render() {\n return html`\n <div\n chart-container\n @wheel=${(e: WheelEvent) => this.resourceChartController.handleWheelForBody(e, this.container)}\n @touchstart=${(e: TouchEvent) => this.resourceChartController.handleTouchStartForBody(e, this.container)}\n @touchmove=${(e: TouchEvent) => this.resourceChartController.handleTouchMoveForBody(e, this.container)}\n >\n <svg header></svg>\n <svg body></svg>\n </div>\n `\n }\n\n syncTimeScale(detail: { baseWidth: number; level: TimeScale }) {\n this.resourceChartController.syncTimeScale(detail)\n this.requestUpdate()\n }\n\n getHorizontalOffset(): number {\n return this.container.scrollLeft\n }\n\n setHorizontalOffset(offset: number) {\n this.container.scrollLeft = offset\n }\n\n getVerticalOffset(): number {\n return this.container.scrollTop\n }\n\n setVerticalOffset(offset: number) {\n this.container.scrollTop = offset\n }\n}\n"]}
@@ -13,7 +13,7 @@ let OxTaskTooltip = class OxTaskTooltip extends LitElement {
13
13
  static { this.styles = css `
14
14
  :host {
15
15
  position: fixed; /* position: absolute로 변경 */
16
- background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface, #f9f9f9));
16
+ background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface-variant, #f9f9f9));
17
17
  border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));
18
18
  padding: var(--spacing-medium, 10px);
19
19
  border-radius: var(--spacing-medium, 8px);
@@ -48,12 +48,12 @@ let OxTaskTooltip = class OxTaskTooltip extends LitElement {
48
48
  }
49
49
  .label {
50
50
  font-weight: bold;
51
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface-variant, #333));
51
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
52
52
  text-align: right; /* 라벨을 우측 정렬 */
53
53
  }
54
54
  .colon {
55
55
  text-align: center;
56
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
56
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
57
57
  }
58
58
  .value {
59
59
  text-align: left; /* 값을 좌측 정렬 */
@@ -1 +1 @@
1
- {"version":3,"file":"ox-task-tooltip.js","sourceRoot":"","sources":["../../src/ox-task-tooltip.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('ox-task-tooltip')\nexport class OxTaskTooltip extends LitElement {\n static styles = css`\n :host {\n position: fixed; /* position: absolute로 변경 */\n background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface, #f9f9f9));\n border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));\n padding: var(--spacing-medium, 10px);\n border-radius: var(--spacing-medium, 8px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n visibility: hidden;\n z-index: 10;\n max-width: 300px;\n font-family: Roboto;\n font-size: 14px;\n line-height: 1.6;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n transition:\n visibility 0.1s,\n opacity 0.1s;\n opacity: 0; /* 초기에는 보이지 않음 */\n }\n :host([visible]) {\n visibility: visible;\n opacity: 1; /* 보일 때는 불투명 */\n }\n .title {\n font-weight: bold;\n font-size: 16px;\n margin-bottom: 8px;\n color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */\n }\n .detail {\n display: grid;\n grid-template-columns: auto auto 1fr;\n gap: 4px;\n align-items: center;\n }\n .label {\n font-weight: bold;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface-variant, #333));\n text-align: right; /* 라벨을 우측 정렬 */\n }\n .colon {\n text-align: center;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n }\n .value {\n text-align: left; /* 값을 좌측 정렬 */\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n }\n `\n\n @property({ type: String }) title = ''\n @property({ type: String }) startDate = ''\n @property({ type: String }) endDate = ''\n @property({ type: Number }) progress = 0\n @property({ type: String }) type = ''\n\n show(x: number, y: number) {\n const tooltipWidth = this.offsetWidth\n const tooltipHeight = this.offsetHeight\n const offsetX = 10\n const offsetY = 10\n\n // 기본 위치 계산\n let left = x + offsetX\n let top = y + offsetY\n\n // 화면 경계 확인 및 조정\n const screenWidth = window.innerWidth\n const screenHeight = window.innerHeight\n\n if (left + tooltipWidth > screenWidth) {\n left = x - tooltipWidth - offsetX\n }\n if (top + tooltipHeight > screenHeight) {\n top = y - tooltipHeight - offsetY\n }\n\n // offsetParent 요소를 기준으로 위치 설정\n if (this.offsetParent) {\n const parentRect = this.offsetParent!.getBoundingClientRect()\n this.style.left = `${left - parentRect.left}px`\n this.style.top = `${top - parentRect.top}px`\n } else {\n this.style.left = `${left}px`\n this.style.top = `${top}px`\n\n const myRect = this.getBoundingClientRect()\n\n /* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */\n if (myRect.left !== left || myRect.top !== top) {\n this.style.left = `${left + (left - myRect.left)}px`\n this.style.top = `${top + (top - myRect.top)}px`\n }\n }\n\n this.setAttribute('visible', '')\n }\n\n hide() {\n this.removeAttribute('visible')\n }\n\n render() {\n return html`\n <div class=\"title\">${this.title}</div>\n <div class=\"detail\">\n <span class=\"label\">Type</span><span class=\"colon\">:</span><span class=\"value\">${this.type}</span>\n <span class=\"label\">Start Date</span><span class=\"colon\">:</span><span class=\"value\">${this.startDate}</span>\n <span class=\"label\">End Date</span><span class=\"colon\">:</span><span class=\"value\">${this.endDate}</span>\n <span class=\"label\">Progress</span><span class=\"colon\">:</span><span class=\"value\">${this.progress}%</span>\n </div>\n `\n }\n}\n"]}
1
+ {"version":3,"file":"ox-task-tooltip.js","sourceRoot":"","sources":["../../src/ox-task-tooltip.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('ox-task-tooltip')\nexport class OxTaskTooltip extends LitElement {\n static styles = css`\n :host {\n position: fixed; /* position: absolute로 변경 */\n background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface-variant, #f9f9f9));\n border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));\n padding: var(--spacing-medium, 10px);\n border-radius: var(--spacing-medium, 8px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n visibility: hidden;\n z-index: 10;\n max-width: 300px;\n font-family: Roboto;\n font-size: 14px;\n line-height: 1.6;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n transition:\n visibility 0.1s,\n opacity 0.1s;\n opacity: 0; /* 초기에는 보이지 않음 */\n }\n :host([visible]) {\n visibility: visible;\n opacity: 1; /* 보일 때는 불투명 */\n }\n .title {\n font-weight: bold;\n font-size: 16px;\n margin-bottom: 8px;\n color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */\n }\n .detail {\n display: grid;\n grid-template-columns: auto auto 1fr;\n gap: 4px;\n align-items: center;\n }\n .label {\n font-weight: bold;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));\n text-align: right; /* 라벨을 우측 정렬 */\n }\n .colon {\n text-align: center;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));\n }\n .value {\n text-align: left; /* 값을 좌측 정렬 */\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n }\n `\n\n @property({ type: String }) title = ''\n @property({ type: String }) startDate = ''\n @property({ type: String }) endDate = ''\n @property({ type: Number }) progress = 0\n @property({ type: String }) type = ''\n\n show(x: number, y: number) {\n const tooltipWidth = this.offsetWidth\n const tooltipHeight = this.offsetHeight\n const offsetX = 10\n const offsetY = 10\n\n // 기본 위치 계산\n let left = x + offsetX\n let top = y + offsetY\n\n // 화면 경계 확인 및 조정\n const screenWidth = window.innerWidth\n const screenHeight = window.innerHeight\n\n if (left + tooltipWidth > screenWidth) {\n left = x - tooltipWidth - offsetX\n }\n if (top + tooltipHeight > screenHeight) {\n top = y - tooltipHeight - offsetY\n }\n\n // offsetParent 요소를 기준으로 위치 설정\n if (this.offsetParent) {\n const parentRect = this.offsetParent!.getBoundingClientRect()\n this.style.left = `${left - parentRect.left}px`\n this.style.top = `${top - parentRect.top}px`\n } else {\n this.style.left = `${left}px`\n this.style.top = `${top}px`\n\n const myRect = this.getBoundingClientRect()\n\n /* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */\n if (myRect.left !== left || myRect.top !== top) {\n this.style.left = `${left + (left - myRect.left)}px`\n this.style.top = `${top + (top - myRect.top)}px`\n }\n }\n\n this.setAttribute('visible', '')\n }\n\n hide() {\n this.removeAttribute('visible')\n }\n\n render() {\n return html`\n <div class=\"title\">${this.title}</div>\n <div class=\"detail\">\n <span class=\"label\">Type</span><span class=\"colon\">:</span><span class=\"value\">${this.type}</span>\n <span class=\"label\">Start Date</span><span class=\"colon\">:</span><span class=\"value\">${this.startDate}</span>\n <span class=\"label\">End Date</span><span class=\"colon\">:</span><span class=\"value\">${this.endDate}</span>\n <span class=\"label\">Progress</span><span class=\"colon\">:</span><span class=\"value\">${this.progress}%</span>\n </div>\n `\n }\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import * as d3 from 'd3';
3
+ import { TimeScale, Task, Resource } from './types';
4
+ export declare class ResourceChartController implements ReactiveController {
5
+ private host;
6
+ private fromTime;
7
+ private toTime;
8
+ private totalDays;
9
+ private _timeScale?;
10
+ private touchStartY?;
11
+ private touchStartX?;
12
+ private scrollStartX?;
13
+ private scrollStartY?;
14
+ baseWidth: number;
15
+ level: TimeScale;
16
+ resources: Resource[];
17
+ tasks: Task[];
18
+ constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale);
19
+ hostConnected(): void;
20
+ get timeScale(): d3.ScaleTime<number, number, never>;
21
+ syncTimeScale(detail: {
22
+ baseWidth: number;
23
+ level: TimeScale;
24
+ }): void;
25
+ updateRange(fromDate: string, toDate: string): void;
26
+ setResources(resources: Resource[]): void;
27
+ setTasks(tasks: Task[]): void;
28
+ updateTimeScale(): void;
29
+ getScale(): number;
30
+ getChartWidth(): number;
31
+ drawAxes(svgHeader: SVGElement): void;
32
+ drawBody(svgBody: SVGElement): void;
33
+ renderResourceAllocations(body: d3.Selection<SVGElement, unknown, null, undefined>, ticks: Date[], chartHeight: number): void;
34
+ calculateResourceAllocations(ticks: Date[]): {
35
+ [key: string]: {
36
+ [key: string]: number;
37
+ };
38
+ };
39
+ getTickEnd(tick: Date): Date;
40
+ formatDateKey(start: Date, end: Date): string;
41
+ handleWheelForBody(event: WheelEvent, container: HTMLDivElement): void;
42
+ handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement): void;
43
+ handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement): void;
44
+ }