From 47433cb2c0d2b8264911c09474d8eea8e00b8e27 Mon Sep 17 00:00:00 2001 From: shufufufu Date: Fri, 9 May 2025 14:21:50 +0800 Subject: [PATCH] feat: add support for text not to be hidden --- docs/assets/demo/en/gantt/gantt-orient.md | 308 ++++++++++++++++++ docs/assets/demo/menu.json | 7 + docs/assets/demo/zh/gantt/gantt-orient.md | 308 ++++++++++++++++++ .../common/gantt/task-bar-label-text-style.md | 5 + .../common/gantt/task-bar-label-text-style.md | 9 +- .../vtable-gantt/src/scenegraph/gantt-node.ts | 7 +- .../vtable-gantt/src/scenegraph/task-bar.ts | 2 +- .../vtable-gantt/src/ts-types/gantt-engine.ts | 2 +- 8 files changed, 641 insertions(+), 7 deletions(-) create mode 100644 docs/assets/demo/en/gantt/gantt-orient.md create mode 100644 docs/assets/demo/zh/gantt/gantt-orient.md diff --git a/docs/assets/demo/en/gantt/gantt-orient.md b/docs/assets/demo/en/gantt/gantt-orient.md new file mode 100644 index 0000000000..9440e7d7b5 --- /dev/null +++ b/docs/assets/demo/en/gantt/gantt-orient.md @@ -0,0 +1,308 @@ +--- +category: examples +group: gantt +title: Gantt Style — Text Not Hidden +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/gantt-label-text.gif +link: gantt/introduction +option: Gantt#taskBar +--- + +# Gantt Style - Text Not Hidden + +This example demonstrates the style configuration of not hiding taskbar text. + +## Key Configuration + +- `orient` Text orientation relative to the taskbar. Optional values: `left`, `top`, `right`, `bottom`, representing the four directions respectively. +- `orientHandleWithOverflow` Specifies the taskbar text orientation when the label cannot fit within the taskbar. Ignored if `orient` is explicitly set. + +## Code Demo + +```javascript livedemo template=vtable +// import * as VTableGantt from '@visactor/vtable-gantt'; +let ganttInstance; +const records = [ + { + id: 1, + title: 'Software Development', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-24', + end: '2024-07-28', + progress: 100, + priority: 'P0' + }, + { + id: 2, + title: 'Project Feature Review', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-25', + end: '2024-07-27', + progress: 90, + priority: 'P0' + }, + { + id: 3, + title: 'Project Create', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-29', + end: '2024-07-31', + progress: 40, + priority: 'P1' + }, + { + id: 4, + title: 'Develop feature 1', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-30', + end: '2024-08-10', + progress: 30, + priority: 'P1' + }, + { + id: 5, + title: 'Determine project scope', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-01', + end: '2024-08-05', + progress: 60, + priority: 'P0' + }, + { + id: 6, + title: 'Project Status Review', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-06', + end: '2024-08-08', + progress: 10, + priority: 'P0' + }, + { + id: 7, + title: 'Feature Testing', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-09', + end: '2024-08-15', + progress: 70, + priority: 'P1' + }, + { + id: 8, + title: 'Project Complete', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-01', + end: '2024-08-10', + progress: 70, + priority: 'P0' + } +]; + +const columns = [ + { + field: 'title', + title: 'title', + width: 'auto', + sort: true, + tree: true, + editor: 'input' + }, + { + field: 'start', + title: 'start', + width: 'auto', + sort: true, + editor: 'date-input' + }, + { + field: 'end', + title: 'end', + width: 'auto', + sort: true, + editor: 'date-input' + }, + { + field: 'priority', + title: 'priority', + width: 'auto', + sort: true, + editor: 'input' + }, + { + field: 'progress', + title: 'progress', + width: 'auto', + sort: true, + headerStyle: { + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8', + color: 'green' + }, + editor: 'input' + } +]; +const option = { + overscrollBehavior: 'none', + records, + taskListTable: { + columns, + tableWidth: 250, + minTableWidth: 100, + maxTableWidth: 600, + theme: { + headerStyle: { + borderColor: '#e1e4e8', + borderLineWidth: 1, + fontSize: 18, + fontWeight: 'bold', + color: 'red', + bgColor: '#EEF1F5' + }, + bodyStyle: { + borderColor: '#e1e4e8', + borderLineWidth: [1, 0, 1, 0], + fontSize: 16, + color: '#4D4D4D', + bgColor: '#FFF' + } + } + //rightFrozenColCount: 1 + }, + frame: { + outerFrameStyle: { + borderLineWidth: 2, + borderColor: '#e1e4e8', + cornerRadius: 8 + }, + verticalSplitLineMoveable: true, + verticalSplitLine: { + lineColor: '#e1e4e8', + lineWidth: 3 + }, + horizontalSplitLine: { + lineColor: '#e1e4e8', + lineWidth: 3 + } + }, + grid: { + weekendBackgroundColor: '#f8f8f8', + verticalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + horizontalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + } + }, + headerRowHeight: 40, + rowHeight: 40, + taskBar: { + startDateField: 'start', + endDateField: 'end', + progressField: 'progress', + // resizable: false, + moveable: true, + hoverBarStyle: { + barOverlayColor: 'rgba(99, 144, 0, 0.4)' + }, + labelText: '{title} {progress}%', + labelTextStyle: { + fontFamily: 'Arial', + fontSize: 16, + textAlign: 'left', + textOverflow: 'visible', + orientHandleWithOverflow: 'right', + outsideColor: '#333333' + }, + barStyle: { + width: 20, + /** 任务条的颜色 */ + barColor: '#ee8800', + /** 已完成部分任务条的颜色 */ + completedBarColor: '#91e8e0', + /** 任务条的圆角 */ + cornerRadius: 8, + /** 任务条的边框 */ + borderLineWidth: 1, + /** 边框颜色 */ + borderColor: 'black' + }, + milestoneStyle: { + borderColor: 'red', + borderLineWidth: 1, + fillColor: 'green', + width: 15 + } + }, + timelineHeader: { + colWidth: 50, + backgroundColor: '#EEF1F5', + horizontalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + verticalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + scales: [ + { + unit: 'week', + step: 1, + startOfWeek: 'sunday', + format(date) { + return `Week ${date.dateIndex}`; + }, + style: { + fontSize: 20, + fontWeight: 'bold', + color: 'white', + strokeColor: 'black', + textAlign: 'right', + textBaseline: 'bottom', + backgroundColor: '#EEF1F5', + textStick: true + // padding: [0, 30, 0, 20] + } + }, + { + unit: 'day', + step: 1, + format(date) { + return date.dateIndex.toString(); + }, + style: { + fontSize: 20, + fontWeight: 'bold', + color: 'white', + strokeColor: 'black', + textAlign: 'right', + textBaseline: 'bottom', + backgroundColor: '#EEF1F5' + } + } + ] + }, + rowSeriesNumber: { + title: '行号', + dragOrder: true, + headerStyle: { + bgColor: '#EEF1F5', + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8' + } + }, + scrollStyle: { + scrollRailColor: 'RGBA(246,246,246,0.5)', + visible: 'scrolling', + width: 6, + scrollSliderCornerRadius: 2, + scrollSliderColor: '#5cb85c' + } +}; +ganttInstance = new VTableGantt.Gantt(document.getElementById(CONTAINER_ID), option); +window['ganttInstance'] = ganttInstance; +``` diff --git a/docs/assets/demo/menu.json b/docs/assets/demo/menu.json index f1944b1de4..690228b7c5 100644 --- a/docs/assets/demo/menu.json +++ b/docs/assets/demo/menu.json @@ -342,6 +342,13 @@ "zh": "隐藏底部时间刻度", "en": "Gantt Hide Hour Scale" } + }, + { + "path": "gantt-orient", + "title": { + "zh": "甘特图样式-文字不隐藏", + "en": "Gantt Style —— Text Not Hidden" + } } ] }, diff --git a/docs/assets/demo/zh/gantt/gantt-orient.md b/docs/assets/demo/zh/gantt/gantt-orient.md new file mode 100644 index 0000000000..70884216c0 --- /dev/null +++ b/docs/assets/demo/zh/gantt/gantt-orient.md @@ -0,0 +1,308 @@ +--- +category: examples +group: gantt +title: 甘特图样式-文字不隐藏 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/gantt-label-text.gif +link: gantt/introduction +option: Gantt#taskBar +--- + +# 甘特图样式—文字不隐藏 + +该示例展示了甘特图文字不隐藏的样式配置。 + +## 关键配置 + +- `orient` 相对于任务条文字方位位置,可选值:`left`, `top`, `right`, `bottom`,分别代表左、上、右、下四个方向 +- `orientHandleWithOverflow` 只有当文本在 taskbar 中容纳不下时,会根据该方位将文本显示在任务条旁边。当配置 `orient` 时,该配置无效 + +## 代码演示 + +```javascript livedemo template=vtable +// import * as VTableGantt from '@visactor/vtable-gantt'; +let ganttInstance; +const records = [ + { + id: 1, + title: 'Software Development', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-24', + end: '2024-07-28', + progress: 100, + priority: 'P0' + }, + { + id: 2, + title: 'Project Feature Review', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-25', + end: '2024-07-27', + progress: 90, + priority: 'P0' + }, + { + id: 3, + title: 'Project Create', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-29', + end: '2024-07-31', + progress: 40, + priority: 'P1' + }, + { + id: 4, + title: 'Develop feature 1', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-07-30', + end: '2024-08-10', + progress: 30, + priority: 'P1' + }, + { + id: 5, + title: 'Determine project scope', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-01', + end: '2024-08-05', + progress: 60, + priority: 'P0' + }, + { + id: 6, + title: 'Project Status Review', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-06', + end: '2024-08-08', + progress: 10, + priority: 'P0' + }, + { + id: 7, + title: 'Feature Testing', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-09', + end: '2024-08-15', + progress: 70, + priority: 'P1' + }, + { + id: 8, + title: 'Project Complete', + developer: 'liufangfang.jane@bytedance.com', + start: '2024-08-01', + end: '2024-08-10', + progress: 70, + priority: 'P0' + } +]; + +const columns = [ + { + field: 'title', + title: 'title', + width: 'auto', + sort: true, + tree: true, + editor: 'input' + }, + { + field: 'start', + title: 'start', + width: 'auto', + sort: true, + editor: 'date-input' + }, + { + field: 'end', + title: 'end', + width: 'auto', + sort: true, + editor: 'date-input' + }, + { + field: 'priority', + title: 'priority', + width: 'auto', + sort: true, + editor: 'input' + }, + { + field: 'progress', + title: 'progress', + width: 'auto', + sort: true, + headerStyle: { + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8', + color: 'green' + }, + editor: 'input' + } +]; +const option = { + overscrollBehavior: 'none', + records, + taskListTable: { + columns, + tableWidth: 250, + minTableWidth: 100, + maxTableWidth: 600, + theme: { + headerStyle: { + borderColor: '#e1e4e8', + borderLineWidth: 1, + fontSize: 18, + fontWeight: 'bold', + color: 'red', + bgColor: '#EEF1F5' + }, + bodyStyle: { + borderColor: '#e1e4e8', + borderLineWidth: [1, 0, 1, 0], + fontSize: 16, + color: '#4D4D4D', + bgColor: '#FFF' + } + } + //rightFrozenColCount: 1 + }, + frame: { + outerFrameStyle: { + borderLineWidth: 2, + borderColor: '#e1e4e8', + cornerRadius: 8 + }, + verticalSplitLineMoveable: true, + verticalSplitLine: { + lineColor: '#e1e4e8', + lineWidth: 3 + }, + horizontalSplitLine: { + lineColor: '#e1e4e8', + lineWidth: 3 + } + }, + grid: { + weekendBackgroundColor: '#f8f8f8', + verticalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + horizontalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + } + }, + headerRowHeight: 40, + rowHeight: 40, + taskBar: { + startDateField: 'start', + endDateField: 'end', + progressField: 'progress', + // resizable: false, + moveable: true, + hoverBarStyle: { + barOverlayColor: 'rgba(99, 144, 0, 0.4)' + }, + labelText: '{title} {progress}%', + labelTextStyle: { + fontFamily: 'Arial', + fontSize: 16, + textAlign: 'left', + textOverflow: 'visible', + orientHandleWithOverflow: 'right', + outsideColor: '#333333' + }, + barStyle: { + width: 20, + /** 任务条的颜色 */ + barColor: '#ee8800', + /** 已完成部分任务条的颜色 */ + completedBarColor: '#91e8e0', + /** 任务条的圆角 */ + cornerRadius: 8, + /** 任务条的边框 */ + borderLineWidth: 1, + /** 边框颜色 */ + borderColor: 'black' + }, + milestoneStyle: { + borderColor: 'red', + borderLineWidth: 1, + fillColor: 'green', + width: 15 + } + }, + timelineHeader: { + colWidth: 50, + backgroundColor: '#EEF1F5', + horizontalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + verticalLine: { + lineWidth: 1, + lineColor: '#e1e4e8' + }, + scales: [ + { + unit: 'week', + step: 1, + startOfWeek: 'sunday', + format(date) { + return `Week ${date.dateIndex}`; + }, + style: { + fontSize: 20, + fontWeight: 'bold', + color: 'white', + strokeColor: 'black', + textAlign: 'right', + textBaseline: 'bottom', + backgroundColor: '#EEF1F5', + textStick: true + // padding: [0, 30, 0, 20] + } + }, + { + unit: 'day', + step: 1, + format(date) { + return date.dateIndex.toString(); + }, + style: { + fontSize: 20, + fontWeight: 'bold', + color: 'white', + strokeColor: 'black', + textAlign: 'right', + textBaseline: 'bottom', + backgroundColor: '#EEF1F5' + } + } + ] + }, + rowSeriesNumber: { + title: '行号', + dragOrder: true, + headerStyle: { + bgColor: '#EEF1F5', + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8' + } + }, + scrollStyle: { + scrollRailColor: 'RGBA(246,246,246,0.5)', + visible: 'scrolling', + width: 6, + scrollSliderCornerRadius: 2, + scrollSliderColor: '#5cb85c' + } +}; +ganttInstance = new VTableGantt.Gantt(document.getElementById(CONTAINER_ID), option); +window['ganttInstance'] = ganttInstance; +``` diff --git a/docs/assets/option/en/common/gantt/task-bar-label-text-style.md b/docs/assets/option/en/common/gantt/task-bar-label-text-style.md index 1d93d5430c..1071aa2f06 100644 --- a/docs/assets/option/en/common/gantt/task-bar-label-text-style.md +++ b/docs/assets/option/en/common/gantt/task-bar-label-text-style.md @@ -1,6 +1,7 @@ {{ target: common-gantt-task-bar-label-text-style }} The definition of ITaskBarLabelTextStyle is: + ``` export interface ITaskBarLabelTextStyle { fontFamily?: string; @@ -10,5 +11,9 @@ export interface ITaskBarLabelTextStyle { textOverflow?: string; textBaseline?: 'alphabetic' | 'bottom' | 'middle' | 'top'; // Sets the vertical alignment of the text within the cell padding?: number | number[]; + /** Text orientation relative to the taskbar. Optional values: 'left', 'top', 'right', 'bottom', representing the four directions respectively. */ + orient?: 'left' | 'top' | 'right' | 'bottom'; + /** Specifies the taskbar text orientation when the label cannot fit within the taskbar. Ignored if `orient` is explicitly set. */ + orientHandleWithOverflow?: 'left' | 'top' | 'right' | 'bottom'; } ``` diff --git a/docs/assets/option/zh/common/gantt/task-bar-label-text-style.md b/docs/assets/option/zh/common/gantt/task-bar-label-text-style.md index fff8f7c7c4..393723a229 100644 --- a/docs/assets/option/zh/common/gantt/task-bar-label-text-style.md +++ b/docs/assets/option/zh/common/gantt/task-bar-label-text-style.md @@ -1,6 +1,7 @@ {{ target: common-gantt-task-bar-label-text-style }} -ITaskBarLabelTextStyle的定义为: +ITaskBarLabelTextStyle 的定义为: + ``` export interface ITaskBarLabelTextStyle { fontFamily?: string; @@ -10,5 +11,9 @@ export interface ITaskBarLabelTextStyle { textOverflow?: string; textBaseline?: 'alphabetic' | 'bottom' | 'middle' | 'top'; // 设置单元格内文字的垂直对齐方式 padding?: number | number[]; + /** 相对于任务条文字方位位置,可选值:'left', 'top', 'right', 'bottom',分别代表左、上、右、下四个方向 */ + orient?: 'left' | 'top' | 'right' | 'bottom'; + /** 只有当文本在 taskbar 中容纳不下时,会根据该方位将文本显示在任务条旁边。当配置 orient 时,该配置无效 */ + orientHandleWithOverflow?: 'left' | 'top' | 'right' | 'bottom'; } -``` \ No newline at end of file +``` diff --git a/packages/vtable-gantt/src/scenegraph/gantt-node.ts b/packages/vtable-gantt/src/scenegraph/gantt-node.ts index 29dad5cbda..2ef7ec1b0c 100644 --- a/packages/vtable-gantt/src/scenegraph/gantt-node.ts +++ b/packages/vtable-gantt/src/scenegraph/gantt-node.ts @@ -1,4 +1,5 @@ import type { IRect, IText, IGroupGraphicAttribute } from '@visactor/vtable/es/vrender'; +import type { ITaskBarLabelTextStyle } from '../ts-types'; import { Group } from '@visactor/vtable/es/vrender'; import { getTextPos } from '../gantt-helper'; import { toBoxArray } from '../tools/util'; @@ -13,7 +14,7 @@ export class GanttTaskBarNode extends Group { task_index: number; sub_task_index?: number; record?: any; - gantt: any; + labelStyle?: ITaskBarLabelTextStyle; _lastWidth?: number; _lastHeight?: number; @@ -51,7 +52,7 @@ export class GanttTaskBarNode extends Group { GanttTaskBarNode.measureContext = ctx; } - const labelStyle = this.gantt?.parsedOptions?.taskBarLabelStyle || {}; + const labelStyle = this.labelStyle || {}; const { textAlign = 'left', textBaseline = 'middle', @@ -140,7 +141,7 @@ export class GanttTaskBarNode extends Group { this.textLabel.setAttribute('y', defaultPosition.y); this.textLabel.setAttribute('textAlign', textAlign); this.textLabel.setAttribute('fill', color); - this.textLabel.setAttribute('maxLineWidth', barWidth - padding * 2); + this.textLabel.setAttribute('maxLineWidth', barWidth - padding); this.textLabel.setAttribute( 'ellipsis', textOverflow === 'clip' diff --git a/packages/vtable-gantt/src/scenegraph/task-bar.ts b/packages/vtable-gantt/src/scenegraph/task-bar.ts index 2a873cf428..b6cc4f80db 100644 --- a/packages/vtable-gantt/src/scenegraph/task-bar.ts +++ b/packages/vtable-gantt/src/scenegraph/task-bar.ts @@ -279,7 +279,7 @@ export class TaskBar { barGroup.appendChild(label); barGroupBox.textLabel = label; - barGroupBox.gantt = this._scene._gantt; + barGroupBox.labelStyle = this._scene._gantt.parsedOptions.taskBarLabelStyle; barGroupBox.updateTextPosition(); } diff --git a/packages/vtable-gantt/src/ts-types/gantt-engine.ts b/packages/vtable-gantt/src/ts-types/gantt-engine.ts index a2b62c7836..8eacb73cdf 100644 --- a/packages/vtable-gantt/src/ts-types/gantt-engine.ts +++ b/packages/vtable-gantt/src/ts-types/gantt-engine.ts @@ -243,7 +243,7 @@ export interface ITaskBarLabelTextStyle { textOverflow?: string; textBaseline?: 'alphabetic' | 'bottom' | 'middle' | 'top'; // 设置单元格内文字的垂直对齐方式 padding?: number | number[]; - // /** 相对于任务条文字方位位置,可选值:'left', 'top', 'right', 'bottom',分别代表左、上、右、下四个方向 */ + /** 相对于任务条文字方位位置,可选值:'left', 'top', 'right', 'bottom',分别代表左、上、右、下四个方向 */ orient?: 'left' | 'top' | 'right' | 'bottom'; /** 只有当文本在 taskbar 中容纳不下时,会根据该方位将文本显示在任务条旁边。当配置 orient 时,该配置无效 */ orientHandleWithOverflow?: 'left' | 'top' | 'right' | 'bottom';