lodash#max TypeScript Examples
The following examples show how to use
lodash#max.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: analysis-utils.ts From prism-frontend with MIT License | 7 votes |
/**
* Creates Analysis result legend based on data returned from API.
*
* The equal interval method takes the maximum values minus the minimum
* and divides the result by the number of classes, which is the length
* of colors array.
*
* Finally the function calculates the upper end of each class interval
* and assigns a color.
*
* @return LegendDefinition
*/
export function createLegendFromFeatureArray(
features: Feature[],
statistic: AggregationOperations,
): LegendDefinition {
// Extract values based on aggregation operation.
const stats: number[] = features.map(f =>
f.properties && f.properties[statistic] ? f.properties[statistic] : 0,
);
const maxNum = Math.max(...stats);
const minNum = Math.min(...stats);
const colors = ['#fee5d9', '#fcae91', '#fb6a4a', '#de2d26', '#a50f15'];
const delta = (maxNum - minNum) / colors.length;
const legend: LegendDefinition = colors.map((color, index) => {
const breakpoint = Math.ceil(minNum + (index + 1) * delta);
// Make sure you don't have a value greater than maxNum.
const value = Math.min(breakpoint, maxNum);
return { value, color };
});
return legend;
}
Example #2
Source File: analysis-utils.ts From prism-frontend with MIT License | 7 votes |
operations = {
min: (data: number[]) => min(data),
max: (data: number[]) => max(data),
sum, // sum method directly from lodash
mean, // mean method directly from lodash
median: (data: number[]) => {
// eslint-disable-next-line fp/no-mutating-methods
const sortedValues = [...data].sort();
// Odd cases we use the middle value
if (sortedValues.length % 2 !== 0) {
return sortedValues[Math.floor(sortedValues.length / 2)];
}
// Even cases we average the two middles
const floor = sortedValues.length / 2 - 1;
const ceil = sortedValues.length / 2;
return (sortedValues[floor] + sortedValues[ceil]) / 2;
},
}
Example #3
Source File: file.utils.ts From WowUp with GNU General Public License v3.0 | 7 votes |
export async function getLastModifiedFileDate(sourcePath: string): Promise<number> {
const dirFiles = await readDirRecursive(sourcePath);
const dates: number[] = [];
for (const file of dirFiles) {
const stat = await fsp.stat(file);
dates.push(stat.mtimeMs);
}
const latest = max(dates);
return latest;
}
Example #4
Source File: pivot-facet.ts From S2 with MIT License | 6 votes |
/**
* 计算树状模式等宽条件下的列宽
* @returns number
*/
private getAdaptTreeColWidth(col: Node, colLeafNodes: Node[]): number {
// tree row width = [config width, canvas / 2]
const canvasW = this.getCanvasHW().width;
const rowHeaderWidth = Math.min(canvasW / 2, this.getTreeRowHeaderWidth());
// calculate col width
const colSize = Math.max(1, colLeafNodes.length);
const { cellCfg } = this.cfg;
return Math.max(
getCellWidth(cellCfg, this.getColLabelLength(col)),
(canvasW - rowHeaderWidth) / colSize,
);
}
Example #5
Source File: turn.ts From fishbowl with MIT License | 6 votes |
export function drawableCards(
turns: CurrentGameSubscription["games"][0]["turns"],
cards: CurrentGameSubscription["games"][0]["cards"]
) {
const allCompletedCardIds = flatMap(turns, (turn) => turn.completed_card_ids)
const maxCount = max(values(countBy(allCompletedCardIds)))
let completedCardIdsForRound = filter(
groupBy(allCompletedCardIds),
(arr) => arr.length === maxCount
).map((arr) => arr[0])
const remainingIdsForRound = difference(
cards.map((card) => card.id),
completedCardIdsForRound
)
if (remainingIdsForRound.length === 0) {
return cards
} else {
return filter(cards, (card) => remainingIdsForRound.includes(card.id))
}
}
Example #6
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
setConditionShowIndex = <T extends ConditionType>(
conditions: Array<ICondition<T>>,
key: string,
show: boolean,
) => {
const showIndexArr = map(conditions, 'showIndex');
const maxShowIndex = max(showIndexArr) as number;
return map(conditions, (item) => {
return {
...item,
showIndex: key === item.key ? (show ? (maxShowIndex || 0) + 1 : 0) : item.showIndex,
};
});
}
Example #7
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
getInitConditions = <T extends ConditionType>(conditions: Array<ICondition<T>>, valueMap: Obj) => {
const showIndexArr = map(conditions, 'showIndex');
const maxShowIndex = max(showIndexArr) as number;
let curMax = maxShowIndex;
const reConditions = map(conditions, (item) => {
const curValue = valueMap[item.key];
// 有值默认展示
if ((!has(item, 'showIndex') && curValue !== undefined) || (isArray(curValue) && !isEmpty(curValue))) {
curMax += 1;
return { ...item, showIndex: curMax };
}
return { ...item };
});
return reConditions;
}
Example #8
Source File: pivot-facet.ts From S2 with MIT License | 6 votes |
/**
* 计算树状结构行头宽度
* @returns number
*/
private getTreeRowHeaderWidth(): number {
const { rows, dataSet, rowCfg, treeRowsWidth } = this.cfg;
// user drag happened
if (rowCfg?.treeRowsWidth) {
return rowCfg?.treeRowsWidth;
}
// + province/city/level
const treeHeaderLabel = rows
.map((key: string): string => dataSet.getFieldName(key))
.join('/');
const { bolderText: cornerCellTextStyle, icon: cornerIconStyle } =
this.spreadsheet.theme.cornerCell;
// 初始化角头时,保证其在树形模式下不换行,给与两个icon的宽度空余(tree icon 和 action icon),减少复杂的 action icon 判断
const maxLabelWidth =
measureTextWidth(treeHeaderLabel, cornerCellTextStyle) +
cornerIconStyle.size * 2 +
cornerIconStyle.margin?.left +
cornerIconStyle.margin?.right +
this.rowCellTheme.padding?.left +
this.rowCellTheme.padding?.right;
return Math.max(treeRowsWidth, maxLabelWidth);
}
Example #9
Source File: pivot-facet.ts From S2 with MIT License | 6 votes |
/**
* 计算平铺模式等宽条件下的列宽
* @returns number
*/
private getAdaptGridColWidth(colLeafNodes: Node[], rowHeaderWidth?: number) {
const { rows, cellCfg } = this.cfg;
const rowHeaderColSize = rows.length;
const colHeaderColSize = colLeafNodes.length;
const canvasW = this.getCanvasHW().width;
const size = Math.max(1, rowHeaderColSize + colHeaderColSize);
if (!rowHeaderWidth) {
// canvasW / (rowHeader's col size + colHeader's col size) = [celCfg.width, canvasW]
return Math.max(getCellWidth(cellCfg), canvasW / size);
}
// (canvasW - rowHeaderW) / (colHeader's col size) = [celCfg.width, canvasW]
return Math.max(
getCellWidth(cellCfg),
(canvasW - rowHeaderWidth) / colHeaderColSize,
);
}
Example #10
Source File: pivot-facet.ts From S2 with MIT License | 6 votes |
private getColLabelLength(col: Node) {
// 如果 label 字段形如 "["xx","xxx"]",直接获取其长度
const labels = safeJsonParse(col?.value);
if (isArray(labels)) {
return labels.length;
}
// 否则动态采样前50条数据,如果数据value是数组类型,获取其长度
const { dataSet } = this.cfg;
const multiData = dataSet.getMultiData(
col.query,
col.isTotals || col.isTotalMeasure,
);
// 采样前50,根据指标个数获取单元格列宽
const demoData = multiData?.slice(0, 50) ?? [];
const lengths = [];
forEach(demoData, (value) => {
forIn(value, (v: MultiData) => {
if (isObject(v) && v?.values) {
lengths.push(size(v?.values[0]));
}
});
});
return max(lengths) || 1;
}
Example #11
Source File: base-data-set.ts From S2 with MIT License | 6 votes |
public getValueRangeByField(field: string): ValueRange {
const cacheRange = getValueRangeState(this.spreadsheet, field);
if (cacheRange) {
return cacheRange;
}
const fieldValues = compact(
map(this.originData, (item) => {
const value = item[field] as string;
return isNil(value) ? null : Number.parseFloat(value);
}),
);
const range = {
maxValue: max(fieldValues),
minValue: min(fieldValues),
};
setValueRangeState(this.spreadsheet, {
[field]: range,
});
return range;
}
Example #12
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
BarContentRender = (props: IBarProps) => {
const { task, isHover } = props;
const barRef = React.useRef<HTMLDivElement>(null);
const nameRef = React.useRef<HTMLDivElement>(null);
const [linearPercent, setLinearPercent] = React.useState(100);
const barWidth = barRef.current?.offsetWidth || 40;
const nameWidth = nameRef.current?.offsetWidth || 40;
React.useLayoutEffect(() => {
setLinearPercent(((barWidth - 8) / nameWidth) * 100);
}, [barWidth, nameWidth]);
return (
<div className={'relative h-full'} ref={barRef}>
<div className={`flex items-center h-full w-full`}>
<div style={{ flex: `0 0 ${max([barWidth, nameWidth])}px` }} className={` ml-2 `}>
<span
ref={nameRef}
className="text-xs whitespace-nowrap"
style={{
padding: '14px 0',
WebkitMaskImage: `linear-gradient(90deg, rgba(48,38,71,0.80) ${linearPercent}%, rgba(48,38,71,0.32) ${linearPercent}%)`,
}}
>
{task.name}
</span>
</div>
<div className={` ml-1 whitespace-nowrap text-sub text-xs ${isHover ? 'visible' : 'invisible'}`}>
{moment(task.start).format('MM-DD')} ~ {moment(task.end).format('MM-DD')}
</div>
</div>
</div>
);
}
Example #13
Source File: edit-project.component.ts From data-annotator-for-machine-learning with Apache License 2.0 | 6 votes |
minUpdate(e) {
if (this.labelType === 'numericLabel' && this.isMultipleLabel) {
this.checkBoth();
} else {
if (e != null && Number(this.msg.max) >= Number(e) && Number(this.msg.max) !== Number(this.msg.min)) {
this.sizeError = false;
} else {
this.sizeError = true;
}
}
}
Example #14
Source File: edit-project.component.ts From data-annotator-for-machine-learning with Apache License 2.0 | 6 votes |
maxUpdate(e) {
if (this.labelType === 'numericLabel' && this.isMultipleLabel) {
this.checkBoth();
} else {
if (e != null && Number(e) >= Number(this.msg.min) && Number(this.msg.max) !== Number(this.msg.min)) {
this.sizeError = false;
} else {
this.sizeError = true;
}
}
}
Example #15
Source File: github_analyzer.ts From CIAnalyzer with MIT License | 5 votes |
createWorkflowReport(workflowName: string, workflow: WorkflowRunsItem, jobs: JobsItem, tagMap: RepositoryTagMap): WorkflowReport {
const { workflowId, buildNumber, workflowRunId }
= this.createWorkflowParams(workflowName, workflow)
const jobReports: JobReport[] = jobs.map((job) => {
const stepReports: StepReport[] = job.steps!.map((step) => {
const startedAt = new Date(step.started_at!)
const completedAt = new Date(step.completed_at!)
// step
return {
name: step.name,
status: this.normalizeStatus(step.conclusion),
number: step.number,
startedAt,
completedAt,
stepDurationSec: diffSec(startedAt, completedAt)
}
})
const startedAt = new Date(job.started_at)
const completedAt = new Date(job.completed_at!)
// job
return {
workflowRunId: workflowRunId,
buildNumber: buildNumber, // Github Actions job does not have buildNumber
jobId: String(job.id),
jobName: job.name,
status: this.normalizeStatus(job.conclusion),
startedAt,
completedAt,
jobDurationSec: diffSec(startedAt, completedAt),
sumStepsDurationSec: sumBy(stepReports, 'stepDurationSec'),
steps: stepReports,
url: job.html_url ?? '',
executorClass: '',
executorType: '',
executorName: job.runner_name ?? '',
}
})
const createdAt = new Date(workflow.created_at)
const startedAt = min(jobReports.map((job) => job.startedAt )) || createdAt
const completedAt = max(jobReports.map((job) => job.completedAt )) || createdAt
const status = this.normalizeStatus(workflow.conclusion as unknown as string)
// workflow
return {
service: 'github',
workflowId,
buildNumber,
workflowRunId,
workflowName,
createdAt,
trigger: workflow.event,
status,
repository: workflow.repository.full_name,
headSha: workflow.head_sha,
branch: workflow.head_branch ?? '',
tag: tagMap.get(workflow.head_sha) ?? '',
jobs: jobReports,
startedAt,
completedAt,
workflowDurationSec: diffSec(startedAt, completedAt),
sumJobsDurationSec: sumBy(jobReports, 'sumStepsDurationSec'),
successCount: (status === 'SUCCESS') ? 1 : 0,
parameters: [],
queuedDurationSec: diffSec(createdAt, startedAt),
commitMessage: workflow.head_commit?.message ?? '',
actor: workflow.head_commit?.author?.name ?? '',
url: workflow.html_url,
}
}
Example #16
Source File: date-helper.ts From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
let newStartDate: Date = tasks[0].start || 0;
let newEndDate: Date = tasks[0].start || 0;
const timeArr = compact(flatten(tasks.map((item) => [item.start, item.end])));
const minTime = min(timeArr);
const maxTime = max(timeArr);
newStartDate = minTime && new Date(minTime);
newEndDate = maxTime && new Date(maxTime);
if (!newStartDate) {
newStartDate = new Date(moment().subtract(15, 'days'));
}
if (!newEndDate || newEndDate.getTime() === newStartDate.getTime()) {
newEndDate = new Date(moment(newStartDate).subtract(-30, 'days'));
}
// start time is bigger then end time
if (newStartDate.getTime() > newEndDate.getTime()) {
[newStartDate, newEndDate] = [newEndDate, newStartDate];
}
switch (viewMode) {
case ViewMode.Month:
newStartDate = addToDate(newStartDate, -1, 'month');
newStartDate = startOfDate(newStartDate, 'month');
newEndDate = addToDate(newEndDate, 1, 'year');
newEndDate = startOfDate(newEndDate, 'year');
break;
case ViewMode.Week:
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(getMonday(newStartDate), -7, 'day');
newEndDate = addToDate(newEndDate, 1.5, 'month');
break;
case ViewMode.Day:
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(newStartDate, -1, 'day');
newEndDate = addToDate(newEndDate, 19, 'day');
break;
case ViewMode.QuarterDay:
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(newStartDate, -1, 'day');
newEndDate = addToDate(newEndDate, 66, 'hour'); // 24(1 day)*3 - 6
break;
case ViewMode.HalfDay:
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(newStartDate, -1, 'day');
newEndDate = addToDate(newEndDate, 108, 'hour'); // 24(1 day)*5 - 12
break;
default:
break;
}
return [newStartDate, newEndDate];
}
Example #17
Source File: task-gantt.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
TaskGantt: React.FC<TaskGanttProps> = ({ gridProps, calendarProps, barProps, BarContentRender }) => {
const ganttSVGRef = useRef<SVGSVGElement>(null);
const newBarProps = { ...barProps, svg: ganttSVGRef };
const verticalGanttContainerRef = useRef<HTMLDivElement>(null);
const offsetWidth = verticalGanttContainerRef?.current?.offsetWidth;
const [mousePos, setMousePos] = React.useState<null | number[]>(null);
const onMouseMove = (e: React.MouseEvent) => {
const gridPos = e.currentTarget.getBoundingClientRect();
const mouseY = max([e.clientY - gridPos.y, 0]);
const mouseX = max([e.clientX - gridPos.x]);
setMousePos([Math.floor(mouseX / gridProps.columnWidth), Math.floor(mouseY / gridProps.rowHeight)]);
};
const mouseUnFocus = () => {
setMousePos(null);
};
return (
<div className={'erda-gantt-vertical-container'} dir="ltr" ref={verticalGanttContainerRef}>
<Calendar
{...calendarProps}
width={max([calendarProps.width, offsetWidth])}
displayWidth={offsetWidth}
mousePos={mousePos}
/>
<svg
xmlns="http://www.w3.org/2000/svg"
width={max([gridProps.svgWidth, offsetWidth])}
height={barProps.rowHeight * barProps.tasks.length}
fontFamily={barProps.fontFamily}
style={{ overflow: 'visible' }}
ref={ganttSVGRef}
>
<g onMouseMove={onMouseMove} onMouseLeave={mouseUnFocus}>
<Grid
{...gridProps}
svgWidth={max([gridProps.svgWidth, offsetWidth])}
displayWidth={offsetWidth}
onMouseMove={onMouseMove}
mouseUnFocus={mouseUnFocus}
mousePos={mousePos}
/>
</g>
<TaskGanttContent {...newBarProps} displayWidth={offsetWidth} BarContentRender={BarContentRender} />
</svg>
</div>
);
}
Example #18
Source File: edit-project.component.ts From data-annotator-for-machine-learning with Apache License 2.0 | 5 votes |
ngOnInit() {
this.msg = JSON.parse(JSON.stringify(this.msgInEdit));
const al = this.msg.al;
this.previousProjectName = this.msg.projectName;
this.inputProjectName = this.msg.projectName;
this.inputTaskInstruction = this.msg.taskInstructions;
this.inputfrequency = al.frequency ? al.frequency : null;
this.inputTrigger = al.trigger ? al.trigger : null;
this.labelType = this.msg.labelType;
this.isMultipleLabel = this.msg.isMultipleLabel;
this.inputProjectCreator = this.msg.creator;
this.inputProjectAssignee = this.msg.annotator;
let flag = [];
_.cloneDeep(this.msg.annotator).forEach((annotator) => {
for (let i = 0; i < this.msg.userCompleteCase.length; i++) {
if (annotator === this.msg.userCompleteCase[i].user) {
flag.push({
email: annotator,
assignedCase: this.msg.userCompleteCase[i].assignedCase,
completeCase: this.msg.userCompleteCase[i].completeCase,
});
break;
}
}
});
this.assigneeList = flag;
this.ownerList = JSON.parse(JSON.stringify(this.msg.creator));
this.assignmentLogicEdit = this.msg.assignmentLogic;
this.isShowFilename = this.msg.isShowFilename ? 'yes' : 'no';
this.oldMax = this.msg.max;
this.oldMin = this.msg.min;
if (this.labelType === 'numericLabel' && this.isMultipleLabel) {
let mutilNumerics = [];
let categoryList = JSON.parse(this.msg.categoryList);
categoryList.forEach(element => {
const labels = Object.keys(element);
const label = labels[0];
const values = element[label];
const minVal = values[0];
const maxVal = values[1];
mutilNumerics.push(this.formBuilder.group({
status: 'old',
originalLabel: label,
editLabel: label,
oldMinMutilVal: this.formBuilder.control(minVal),
minMutilVal: this.formBuilder.control(minVal),
oldMaxMutilVal: this.formBuilder.control(maxVal),
maxMutilVal: this.formBuilder.control(maxVal),
}));
});
this.mutilNumericForm = this.formBuilder.group({
mutilLabelArray: this.formBuilder.array(mutilNumerics)
});
} else {
this.msg.categoryList.split(',').forEach((element) => {
const flag = { status: 'old', originalLabel: element, editLabel: element };
this.categoryList.push(flag);
});
}
}
Example #19
Source File: pivot-facet.ts From S2 with MIT License | 5 votes |
/**
* 计算 compact 模式下 node 宽度
*
* | fieldName |
* _______________
* | label - icon | <- node
* | label - icon |
* | label - icon |
*
* @param node 目标节点
* @returns 宽度
*/
private getCompactGridRowWidth(node: Node): number {
const { dataSet, spreadsheet } = this.cfg;
const {
bolderText: rowTextStyle,
icon: rowIconStyle,
cell: rowCellStyle,
} = spreadsheet.theme.rowCell;
const {
bolderText: cornerTextStyle,
icon: cornerIconStyle,
cell: cornerCellStyle,
} = spreadsheet.theme.cornerCell;
const { field, isLeaf } = node;
// calc rowNodeWitdh
const rowIconWidth = this.getExpectedCellIconWidth(
CellTypes.ROW_CELL,
!spreadsheet.isValueInCols() &&
isLeaf &&
spreadsheet.options.showDefaultHeaderActionIcon,
rowIconStyle,
);
const allLabels = dataSet
.getDimensionValues(field)
?.slice(0, 50)
.map(
(dimValue) =>
this.spreadsheet.dataSet.getFieldFormatter(field)?.(dimValue) ??
dimValue,
);
const maxLabel = maxBy(allLabels, (label) => `${label}`.length);
const rowNodeWidth =
measureTextWidth(maxLabel, rowTextStyle) +
rowIconWidth +
rowCellStyle.padding.left +
rowCellStyle.padding.right;
// calc corner fieldNameNodeWidth
const fieldName = dataSet.getFieldName(field);
const cornerIconWidth = this.getExpectedCellIconWidth(
CellTypes.CORNER_CELL,
false,
cornerIconStyle,
);
const fieldNameNodeWidth =
measureTextWidth(fieldName, cornerTextStyle) +
cornerIconWidth +
cornerCellStyle.padding.left +
cornerCellStyle.padding.right;
DebuggerUtil.getInstance().logger(
'Max Label In Row:',
field,
rowNodeWidth > fieldNameNodeWidth ? maxLabel : fieldName,
);
// return max
return Math.max(rowNodeWidth, fieldNameNodeWidth);
}
Example #20
Source File: circleci_runner_v2.ts From CIAnalyzer with MIT License | 5 votes |
private setRepoLastRun(reponame: string, pipelines: Pipeline[]) {
const maxBuildNumber = max(pipelines.map((pipeline) => pipeline.number))
if (maxBuildNumber) {
this.store?.setLastRun(reponame, maxBuildNumber)
}
}
Example #21
Source File: circleci_client.ts From CIAnalyzer with MIT License | 5 votes |
// https://circleci.com/api/v1.1/project/:vcs-type/:username/:project?circle-token=:token&limit=20&offset=5&filter=completed
async fetchWorkflowRuns(owner: string, repo: string, vcsType: string, lastRunId?: number) {
const limit = (this.options.debug) ? DEBUG_PER_PAGE : 100
let recentBuilds = [] as RecentBuildResponse[]
for (let index = 0; index < FETCH_RECENT_BUILD_API_NUM; index++) {
const res = await this.axios.get( `project/${vcsType}/${owner}/${repo}`, {
params: {
// API default is 30 and max is 100
// ref: https://circleci.com/docs/api/#recent-builds-for-a-single-project
limit: limit,
// limit: 3,
offset: index * limit,
// filter: "completed"
shallow: true,
}
})
recentBuilds.push(...res.data)
}
recentBuilds = (lastRunId)
? recentBuilds.filter((build) => build.build_num > lastRunId)
: recentBuilds
// Add dummy workflow data if job is not belong to workflow
for (const build of recentBuilds) {
if (!build.workflows) {
build.workflows = this.createDefaultWorkflow(build)
}
}
const groupedBuilds = groupBy(recentBuilds.map((build) => {
return {
workflow_name: build.workflows.workflow_name,
workflow_id: build.workflows.workflow_id,
reponame: build.reponame,
username: build.username,
vcs_type: vcsType,
build_num: build.build_num,
lifecycle: build.lifecycle,
}
}), 'workflow_id')
const workflowRuns: WorkflowRun[] = Object.values(groupedBuilds).map((builds) => {
const build = builds[0]
const build_nums = builds.map((build) => build.build_num)
return {
workflow_id: build.workflow_id,
workflow_name: build.workflow_name,
reponame: build.reponame,
username: build.username,
vcs_type: build.vcs_type,
build_nums,
lifecycles: builds.map((build) => build.lifecycle),
last_build_num: max(build_nums)!,
}
})
return this.filterWorkflowRuns(workflowRuns)
}
Example #22
Source File: time-series.spec.ts From aqualink-app with MIT License | 4 votes |
timeSeriesTests = () => {
const testService = TestService.getInstance();
let app: INestApplication;
let surveyPointDataRange: StringDateRange = [
new Date(0).toISOString(),
new Date().toISOString(),
];
let siteDataRange: StringDateRange = [
new Date(0).toISOString(),
new Date().toISOString(),
];
beforeAll(async () => {
app = await testService.getApp();
});
it('GET /sites/:siteId/site-survey-points/:surveyPointId/range fetch range of poi data', async () => {
const rsp = await request(app.getHttpServer()).get(
`/time-series/sites/${athensSite.id}/site-survey-points/${athensSurveyPointPiraeus.id}/range`,
);
expect(rsp.status).toBe(200);
const metrics = union(hoboMetrics, NOAAMetrics);
metrics.forEach((metric) => {
expect(rsp.body).toHaveProperty(metric);
});
hoboMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.HOBO);
expect(rsp.body[metric][SourceType.HOBO].data.length).toBe(1);
const { minDate, maxDate } = rsp.body[metric][SourceType.HOBO].data[0];
const [startDate, endDate] = surveyPointDataRange;
surveyPointDataRange = [
min([minDate, startDate]),
max([maxDate, endDate]),
];
});
NOAAMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.NOAA);
expect(rsp.body[metric][SourceType.NOAA].data.length).toBe(1);
const { minDate, maxDate } = rsp.body[metric][SourceType.NOAA].data[0];
const [startDate, endDate] = surveyPointDataRange;
surveyPointDataRange = [
min([minDate, startDate]),
max([maxDate, endDate]),
];
});
});
it('GET /sites/:id/range fetch range of site data', async () => {
const rsp = await request(app.getHttpServer()).get(
`/time-series/sites/${californiaSite.id}/range`,
);
expect(rsp.status).toBe(200);
const metrics = union(NOAAMetrics, spotterMetrics);
metrics.forEach((metric) => {
expect(rsp.body).toHaveProperty(metric);
});
NOAAMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.NOAA);
expect(rsp.body[metric][SourceType.NOAA].data.length).toBe(1);
const { minDate, maxDate } = rsp.body[metric][SourceType.NOAA].data[0];
const [startDate, endDate] = siteDataRange;
siteDataRange = [min([minDate, startDate]), max([maxDate, endDate])];
});
spotterMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.SPOTTER);
expect(rsp.body[metric][SourceType.SPOTTER].data.length).toBe(1);
const { minDate, maxDate } = rsp.body[metric][SourceType.SPOTTER].data[0];
const [startDate, endDate] = siteDataRange;
siteDataRange = [min([minDate, startDate]), max([maxDate, endDate])];
});
});
it('GET /sites/:siteId/site-survey-points/:surveyPointId fetch poi data', async () => {
const [startDate, endDate] = surveyPointDataRange;
const rsp = await request(app.getHttpServer())
.get(
`/time-series/sites/${athensSite.id}/site-survey-points/${athensSurveyPointPiraeus.id}`,
)
.query({
// Increase the search window to combat precision issues with the dates
start: moment(startDate).subtract(1, 'minute').toISOString(),
end: moment(endDate).add(1, 'day').toISOString(),
metrics: hoboMetrics.concat(NOAAMetrics),
hourly: false,
});
expect(rsp.status).toBe(200);
const metrics = union(hoboMetrics, NOAAMetrics);
metrics.forEach((metric) => {
expect(rsp.body).toHaveProperty(metric);
});
hoboMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.HOBO);
expect(rsp.body[metric][SourceType.HOBO].data.length).toBe(10);
});
NOAAMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.NOAA);
expect(rsp.body[metric][SourceType.NOAA].data.length).toBe(10);
});
});
it('GET /sites/:siteId fetch site data', async () => {
const [startDate, endDate] = siteDataRange;
const rsp = await request(app.getHttpServer())
.get(`/time-series/sites/${californiaSite.id}`)
.query({
// Increase the search window to combat precision issues with the dates
start: moment(startDate).subtract(1, 'minute').toISOString(),
end: moment(endDate).add(1, 'day').toISOString(),
metrics: spotterMetrics.concat(NOAAMetrics),
hourly: false,
});
expect(rsp.status).toBe(200);
const metrics = union(NOAAMetrics, spotterMetrics);
metrics.forEach((metric) => {
expect(rsp.body).toHaveProperty(metric);
});
NOAAMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.NOAA);
expect(rsp.body[metric][SourceType.NOAA].data.length).toBe(10);
});
spotterMetrics.forEach((metric) => {
expect(rsp.body[metric]).toHaveProperty(SourceType.SPOTTER);
expect(rsp.body[metric][SourceType.SPOTTER].data.length).toBe(10);
});
});
}
Example #23
Source File: philosophers.tsx From S2 with MIT License | 4 votes |
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/24cac0f7-70f0-4131-be61-df11da3ca921.json',
)
.then((res) => res.json())
.then((data) => {
const weights = data.map((item) => item.weight);
const maxWeight = max(weights);
const minWeight = min(weights);
const weightSpan = maxWeight - minWeight;
const PaletteLegend = () => (
<div className="legend">
<div className="legend-limit">{minWeight.toFixed(2)}</div>
{PALETTE_COLORS.map((color, index) => (
<span
key={index}
className="legend-color"
style={{ background: color }}
/>
))}
<div className="legend-limit">{maxWeight.toFixed(2)}</div>
</div>
);
const getFormatter = (val) => {
if (val < 0) {
return `公元前${replace(val, '-', '')}年`;
} else {
return `${val}年`;
}
};
const s2DataConfig = {
fields: {
rows: ['country', 'name', 'start', 'end', 'points', 'word'],
columns: [],
values: ['weight'],
},
meta: [
{
field: 'word',
name: '关键词',
},
{
field: 'points',
name: '观点',
},
{
field: 'name',
name: '姓名',
},
{
field: 'country',
name: '国家',
},
{
field: 'start',
name: '出生',
formatter: getFormatter,
},
{
field: 'end',
name: '逝世',
formatter: getFormatter,
},
{
field: 'weight',
name: '权重',
formatter: (val) => val.toFixed(2),
},
],
data,
};
const TooltipContent = (props) => {
const { rowQuery, fieldValue } = props;
const { name, country, start, end, points } = rowQuery;
const ponitsLines = points.split('&');
return (
<div className="antv-s2-tooltip-container">
<div className="antv-s2-tooltip-head-info-list">
<div>姓名:{name}</div>
<div>国家:{country}</div>
<div>出生:{getFormatter(start)}</div>
<div>逝世:{getFormatter(end)}</div>
{ponitsLines.length > 1 ? (
<div>
观点:
{ponitsLines.map((point, index) => (
<div>
{index + 1}: {point}
</div>
))}
</div>
) : (
<div>观点: {ponitsLines[0]}</div>
)}
</div>
<div className="antv-s2-tooltip-divider"></div>
<div className="antv-s2-tooltip-detail-list">
<div className="antv-s2-tooltip-detail-item">
<span className="antv-s2-tooltip-detail-item-key">权重</span>
<span className="antv-s2-tooltip-detail-item-val">
{fieldValue}
</span>
</div>
</div>
</div>
);
};
const s2Options = {
width: '',
height: 400,
conditions: {
text: [
{
field: 'weight',
mapping(value) {
if (value >= 20) {
return {
fill: '#fff',
};
}
},
},
],
background: [
{
field: 'weight',
mapping(value) {
let backgroundColor;
const colorIndex =
Math.floor(
(((value - minWeight) / weightSpan) * 100) /
PALETTE_COLORS.length,
) - 1;
if (colorIndex <= 0) {
backgroundColor = PALETTE_COLORS[0];
} else if (colorIndex >= PALETTE_COLORS.length) {
backgroundColor = PALETTE_COLORS[PALETTE_COLORS.length - 1];
} else {
backgroundColor = PALETTE_COLORS[colorIndex];
}
return {
fill: backgroundColor,
};
},
},
],
},
interaction: {
selectedCellsSpotlight: false,
hoverHighlight: false,
},
};
const onDataCellMouseUp = (value) => {
const viewMeta = value?.viewMeta;
if (!viewMeta) {
return;
}
const position = {
x: value.event.clientX,
y: value.event.clientY,
};
viewMeta.spreadsheet.tooltip.show({
position,
content: TooltipContent(viewMeta),
});
};
ReactDOM.render(
<SheetComponent
dataCfg={s2DataConfig}
options={s2Options}
adaptive={true}
header={{
title: '哲学家的观点',
extra: [<PaletteLegend />],
}}
onDataCellMouseUp={onDataCellMouseUp}
/>,
document.getElementById('container'),
);
});
Example #24
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
TagsRow = ({
labels: propsLabels,
showCount = 2,
containerClassName = '',
labelsClassName = '',
size = 'small',
colorMap,
onDelete,
onAdd,
}: IProps) => {
const labels = propsLabels ? (Array.isArray(propsLabels) ? propsLabels : [propsLabels]) : [];
const showMore = labels.length > showCount;
const showGroup = some(labels, (l) => has(l, 'group'));
const [labelWidth, setLabelWidth] = React.useState<string | number>('auto');
const countLabelWidth = () => {
const labelEles = document.querySelectorAll('.tag-group-name');
const maxWidth: number = max(map(labelEles, (ele: HTMLSpanElement) => ele.offsetWidth));
setLabelWidth(Math.min(maxWidth, MAX_LABEL_WIDTH) + 8);
};
const fullTags = () => {
if (showGroup) {
return (
<div>
{map(groupBy(labels, 'group'), (groupItem, gKey) => (
<div key={gKey} className="tag-group-container mb-2">
<span className="tag-group-name" style={{ width: labelWidth }}>{`${gKey} : `}</span>
<span className="flex-1 overflow-auto">
{groupItem.map((item) => (
<TagItem colorMap={colorMap} key={item.label} label={item} onDelete={onDelete} size={size} />
))}
</span>
</div>
))}
</div>
);
}
return labels.map((l) => <TagItem colorMap={colorMap} key={l.label} label={l} onDelete={onDelete} size={size} />);
};
const oneAndMoreTag = (
<React.Fragment>
{labels.slice(0, showCount).map((l) => (
<TagItem colorMap={colorMap} key={l.label} label={l} maxWidth={100} onDelete={onDelete} size={size} />
))}
{showMore ? (
<Tooltip
onVisibleChange={(vis) => {
if (vis && labelWidth === 'auto') {
countLabelWidth();
}
}}
title={
<div onClick={(e) => e.stopPropagation()} className="tags-container ">
{fullTags()}
</div>
}
placement="right"
overlayClassName="tags-row-tooltip"
>
<ErdaIcon className={`twt-tag-ellipsis ${size}`} type="more" color="currentColor" />
</Tooltip>
) : null}
</React.Fragment>
);
return (
<div
className={`tags-container flex items-center justify-start overflow-hidden ${containerClassName}`}
onClick={(e) => e.stopPropagation()}
>
<span className={`tags-box flex items-center ${labelsClassName}`}>{oneAndMoreTag}</span>
{onAdd ? (
<ErdaIcon
className={`tags-add ${size} ml-2 text-xs leading-6 cursor-pointer`}
type="plus"
color="currentColor"
onClick={onAdd}
/>
) : null}
</div>
);
}
Example #25
Source File: calendar.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
Calendar: React.FC<CalendarProps> = React.memo(
({
dateSetup,
locale,
viewMode,
rtl,
width,
height,
columnWidth,
horizontalRange,
fontFamily,
fontSize,
highlightRange,
displayWidth,
scrollX,
setScrollX,
svgWidth,
mousePos,
}) => {
const today = new Date();
const getCalendarValuesForMonth = () => {
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
const topDefaultHeight = height * 0.5;
for (let i = 0; i < dateSetup.dates.length; i++) {
const date = dateSetup.dates[i];
const bottomValue = getLocaleMonth(date, locale);
bottomValues.push(
<text
key={bottomValue + date.getFullYear()}
y={height * 0.8}
x={columnWidth * i + columnWidth * 0.5}
className={'erda-gantt-calendar-bottom-text'}
>
{bottomValue}
</text>,
);
if (i === 0 || date.getFullYear() !== dateSetup.dates[i - 1].getFullYear()) {
const topValue = date.getFullYear().toString();
let xText: number;
if (rtl) {
xText = (6 + i + date.getMonth() + 1) * columnWidth;
} else {
xText = (6 + i - date.getMonth()) * columnWidth;
}
topValues.push(
<TopPartOfCalendar
key={topValue}
value={topValue}
x1Line={columnWidth * i}
y1Line={0}
y2Line={topDefaultHeight}
xText={xText}
yText={topDefaultHeight * 0.9}
/>,
);
}
}
return [topValues, bottomValues];
};
const getCalendarValuesForWeek = () => {
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
let weeksCount = 1;
const topDefaultHeight = height * 0.5;
const { dates } = dateSetup;
for (let i = dates.length - 1; i >= 0; i--) {
const date = dates[i];
let topValue = '';
if (i === 0 || date.getMonth() !== dates[i - 1].getMonth()) {
// top
topValue = `${getLocaleMonth(date, locale)}, ${date.getFullYear()}`;
}
// bottom
const bottomValue = `W${getWeekNumberISO8601(date)}`;
bottomValues.push(
<text
key={date.getTime()}
y={height * 0.8}
x={columnWidth * (i + +rtl)}
className={'erda-gantt-calendar-bottom-text'}
>
{bottomValue}
</text>,
);
if (topValue) {
// if last day is new month
if (i !== dates.length - 1) {
topValues.push(
<TopPartOfCalendar
key={topValue}
value={topValue}
x1Line={columnWidth * i + weeksCount * columnWidth}
y1Line={0}
y2Line={topDefaultHeight}
xText={columnWidth * i + columnWidth * weeksCount * 0.5}
yText={topDefaultHeight * 0.9}
/>,
);
}
weeksCount = 0;
}
weeksCount++;
}
return [topValues, bottomValues];
};
const reHighlightRange = {
...highlightRange,
...(highlightRange?.id && !highlightRange.start && !highlightRange.end ? { x1: -1, x2: -1 } : {}),
};
const HoverBar = ({ style }: { style: Obj }) =>
highlightRange ? (
<div
className="absolute rounded bg-black-06"
style={{
width: Math.abs(reHighlightRange.x2 - reHighlightRange.x1),
height: 40,
left: min([reHighlightRange.x1, reHighlightRange.x2]),
top: 26,
...style,
}}
/>
) : null;
const HoverTime = ({ style }: { style: Obj }) =>
mousePos ? (
<div
className="absolute rounded bg-black-06"
style={{
width: columnWidth,
height: 40,
left: mousePos[0] * columnWidth,
top: 26,
...style,
}}
/>
) : null;
const onChangeScrollX = (direction: number) => {
const moveLen = Math.floor(displayWidth / columnWidth) - 4; // less then display count;
const moveX = moveLen > 0 ? moveLen * columnWidth : columnWidth;
if (direction === -1) {
setScrollX((prevX) => (moveX >= prevX ? -1 : prevX - moveX));
} else if (direction === 1) {
setScrollX((prevX) => (moveX + prevX + displayWidth >= svgWidth ? svgWidth - displayWidth : prevX + moveX));
}
};
const getCalendarValuesForDay = () => {
let bottomValues: React.ReactNode = null;
const dates = dateSetup.dates.slice(...horizontalRange);
const dateInWeeks = [];
// append date when screen have more space
if (!dates.length) return null;
let appendDateLength = Math.max(0, horizontalRange[1] - horizontalRange[0] - dates.length);
while (appendDateLength-- > 0) {
const lastDayInLastWeek = dates[dates.length - 1];
dates.push(addToDate(lastDayInLastWeek, 1, 'day'));
}
const firstDay = dates[0];
const firstDayInWeek = firstDay.getDay();
// use Monday as first day of week
const firstWeek = dates.splice(0, firstDayInWeek === 0 ? 1 : 7 - firstDayInWeek + 1);
while (firstWeek.length < 7) {
const firstDayInFirstWeek = firstWeek[0];
firstWeek.unshift(addToDate(firstDayInFirstWeek, -1, 'day'));
}
dateInWeeks.push(firstWeek);
while (dates.length) {
dateInWeeks.push(dates.splice(0, 7));
}
const lastWeek = dateInWeeks[dateInWeeks.length - 1];
while (lastWeek.length < 7) {
const lastDayInLastWeek = lastWeek[lastWeek.length - 1];
lastWeek.push(addToDate(lastDayInLastWeek, 1, 'day'));
}
const offsetX = (firstDayInWeek ? firstDayInWeek - 1 : 6) * columnWidth;
bottomValues = (
<div
className="flex h-full w-full erda-gantt-calendar-header-container"
style={{ transform: `translateX(${-offsetX}px)` }}
>
{<HoverBar style={{ transform: `translateX(${offsetX}px)` }} />}
{<HoverTime style={{ transform: `translateX(${offsetX}px)` }} />}
{flatten(dateInWeeks).map((day, idx) => {
const mark =
reHighlightRange?.x1 === columnWidth * idx - offsetX ||
reHighlightRange?.x2 === columnWidth * (idx + 1) - offsetX;
const cls = `${
mark
? 'calendar-highlight-text'
: `${[0, 6].includes(day.getDay()) ? 'calendar-disabled-text' : 'calendar-normal-text'}`
}`;
const isStartPos = columnWidth * idx - offsetX === 0;
const isToday = moment(day).isSame(today, 'day');
return (
<div
key={day.getTime()}
style={{
width: columnWidth,
height: 40,
top: 28,
left: columnWidth * idx,
}}
className={`absolute flex flex-col items-center text-xs justify-center ${cls} ${
isToday ? 'text-red' : ''
}`}
>
<span>{Days[day.getDay()]}</span>
<span>{day.getDate()}</span>
{isStartPos || day.getDate() === 1 ? (
<div className="absolute text-default-8 font-medium " style={{ top: -16 }}>
{Months[day.getMonth()]}
</div>
) : null}
{isToday ? (
<div
style={{ left: (columnWidth + 22) / 2, bottom: -14 }}
className="absolute erda-gantt-calendar-today flex justify-center"
>
<div>{i18n.t('dop:Today')}</div>
</div>
) : null}
</div>
);
})}
{scrollX > 0 ? (
<div
className="flex items-center erda-gantt-calendar-arrow-left"
onClick={() => onChangeScrollX(-1)}
style={{ left: offsetX }}
>
<ErdaIcon type="zuofan" className="ml-1" size={10} />
</div>
) : null}
{displayWidth + scrollX < svgWidth ? (
<div
className="flex items-center erda-gantt-calendar-arrow-right"
onClick={() => onChangeScrollX(1)}
style={{ left: offsetX + displayWidth - 16 }}
>
<ErdaIcon type="youfan" className="ml-1" size={10} />
</div>
) : null}
</div>
);
return bottomValues;
};
const getCalendarValuesForOther = () => {
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
const ticks = viewMode === ViewMode.HalfDay ? 2 : 4;
const topDefaultHeight = height * 0.5;
const { dates } = dateSetup;
for (let i = 0; i < dates.length; i++) {
const date = dates[i];
const bottomValue = getCachedDateTimeFormat(locale, {
hour: 'numeric',
}).format(date);
bottomValues.push(
<text
key={date.getTime()}
y={height * 0.8}
x={columnWidth * (i + +rtl)}
className={'erda-gantt-calendar-bottom-text'}
fontFamily={fontFamily}
>
{bottomValue}
</text>,
);
if (i === 0 || date.getDate() !== dates[i - 1].getDate()) {
const topValue = `${date.getDate()} ${getLocaleMonth(date, locale)}`;
topValues.push(
<TopPartOfCalendar
key={topValue + date.getFullYear()}
value={topValue}
x1Line={columnWidth * i + ticks * columnWidth}
y1Line={0}
y2Line={topDefaultHeight}
xText={columnWidth * i + ticks * columnWidth * 0.5}
yText={topDefaultHeight * 0.9}
/>,
);
}
}
return [topValues, bottomValues];
};
// let topValues: ReactChild[] = [];
// let bottomValues: ReactChild[] = [];
// switch (dateSetup.viewMode) {
// // case ViewMode.Month:
// // [topValues, bottomValues] = getCalendarValuesForMonth();
// // break;
// // case ViewMode.Week:
// // [topValues, bottomValues] = getCalendarValuesForWeek();
// // break;
// case ViewMode.Day:
// [topValues, bottomValues] = getCalendarValuesForDay();
// break;
// default:
// [topValues, bottomValues] = getCalendarValuesForOther();
// break;
// }
const finalWidth = max([columnWidth * dateSetup.dates.length, width]);
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="overflow-visible"
width={width}
height={height}
fontFamily={fontFamily}
>
<g className="erda-gantt-calendar" fontSize={fontSize}>
<rect x={0} y={0} width={finalWidth} height={height} className={'erda-gantt-calendar-header'} />
<foreignObject
x={0}
y={0}
width={finalWidth}
height={height}
className={'erda-gantt-calendar-header overflow-visible'}
>
{getCalendarValuesForDay()}
</foreignObject>
{/* {topValues} */}
</g>
</svg>
);
},
)
Example #26
Source File: index.ts From S2 with MIT License | 4 votes |
copyData = (
sheetInstance: SpreadSheet,
split: string,
formatOptions?: FormatOptions,
): string => {
const { isFormatHeader, isFormatData } = getFormatOptions(formatOptions);
const { rowsHierarchy, rowLeafNodes, colLeafNodes, getCellMeta } =
sheetInstance?.facet?.layoutResult;
const { maxLevel } = rowsHierarchy;
const { valueInCols } = sheetInstance.dataCfg.fields;
// Generate the table header.
const rowsHeader = rowsHierarchy.sampleNodesForAllLevels.map((item) =>
sheetInstance.dataSet.getFieldName(item.key),
);
// get max query property length
const rowLength = rowLeafNodes.reduce((pre, cur) => {
const length = cur.query ? Object.keys(cur.query).length : 0;
return length > pre ? length : pre;
}, 0);
// Generate the table body.
let detailRows = [];
let maxRowLength = 0;
if (!sheetInstance.isPivotMode()) {
detailRows = processValueInDetail(sheetInstance, split, isFormatData);
} else {
// Filter out the related row head leaf nodes.
const caredRowLeafNodes = rowLeafNodes.filter((row) => row.height !== 0);
for (const rowNode of caredRowLeafNodes) {
let tempLine = [];
if (isFormatHeader) {
tempLine = getRowNodeFormatData(rowNode);
} else {
// Removing the space at the beginning of the line of the label.
rowNode.label = trim(rowNode?.label);
const id = rowNode.id.replace(ROOT_BEGINNING_REGEX, '');
tempLine = id.split(ID_SEPARATOR);
}
// TODO 兼容下钻,需要获取下钻最大层级
const totalLevel = maxLevel + 1;
const emptyLength = totalLevel - tempLine.length;
if (emptyLength > 0) {
tempLine.push(...new Array(emptyLength));
}
// 指标挂行头且为平铺模式下,获取指标名称
const lastLabel = sheetInstance.dataSet.getFieldName(last(tempLine));
tempLine[tempLine.length - 1] = lastLabel;
for (const colNode of colLeafNodes) {
if (valueInCols) {
const viewMeta = getCellMeta(rowNode.rowIndex, colNode.colIndex);
tempLine.push(
processValueInCol(viewMeta, sheetInstance, isFormatData),
);
} else {
const viewMeta = getCellMeta(rowNode.rowIndex, colNode.colIndex);
const lintItem = processValueInRow(
viewMeta,
sheetInstance,
isFormatData,
);
if (isArray(lintItem)) {
tempLine = tempLine.concat(...lintItem);
} else {
tempLine.push(lintItem);
}
}
}
maxRowLength = max([tempLine.length, maxRowLength]);
const lineString = tempLine
.map((value) => getCsvString(value))
.join(split);
detailRows.push(lineString);
}
}
// Generate the table header.
let headers: string[][] = [];
if (isEmpty(colLeafNodes) && !sheetInstance.isPivotMode()) {
// when there is no column in detail mode
headers = [rowsHeader];
} else {
// 当列头label为array时用于补全其他层级的label
let arrayLength = 0;
// Get the table header of Columns.
let tempColHeader = clone(colLeafNodes).map((colItem) => {
let curColItem = colItem;
const tempCol = [];
// Generate the column dimensions.
while (curColItem.level !== undefined) {
let label = getHeaderLabel(curColItem.label);
if (isArray(label)) {
arrayLength = max([arrayLength, size(label)]);
} else {
// label 为数组时不进行格式化
label = isFormatHeader ? getNodeFormatLabel(curColItem) : label;
}
tempCol.push(label);
curColItem = curColItem.parent;
}
return tempCol;
});
if (arrayLength > 1) {
tempColHeader = processColHeaders(tempColHeader, arrayLength);
}
const colLevels = tempColHeader.map((colHeader) => colHeader.length);
const colLevel = max(colLevels);
const colHeader: string[][] = [];
// Convert the number of column dimension levels to the corresponding array.
for (let i = colLevel - 1; i >= 0; i -= 1) {
// The map of data set: key-name
const colHeaderItem = tempColHeader
// total col completion
.map((item) =>
item.length < colLevel
? [...new Array(colLevel - item.length), ...item]
: item,
)
.map((item) => item[i])
.map((colItem) => sheetInstance.dataSet.getFieldName(colItem));
colHeader.push(flatten(colHeaderItem));
}
// Generate the table header.
headers = colHeader.map((item, index) => {
if (sheetInstance.isPivotMode()) {
const { columns, rows, data } = sheetInstance.facet.cornerHeader.cfg;
const colNodes = data.filter(
({ cornerType }) => cornerType === CornerNodeType.Col,
);
const rowNodes = data.filter(
({ cornerType }) => cornerType === CornerNodeType.Row,
);
if (index < colHeader.length - 1) {
return [
...Array(rowLength - 1).fill(''),
colNodes.find(({ field }) => field === columns[index])?.label || '',
...item,
];
}
if (index < colHeader.length) {
return [
...rows.map(
(row) => rowNodes.find(({ field }) => field === row)?.label || '',
),
...item,
];
}
return rowsHeader.concat(...item);
}
return index < colHeader.length
? Array(rowLength)
.fill('')
.concat(...item)
: rowsHeader.concat(...item);
});
}
const headerRow = headers
.map((header) => {
const emptyLength = maxRowLength - header.length;
if (emptyLength > 0) {
header.unshift(...new Array(emptyLength));
}
return header.map((h) => getCsvString(h)).join(split);
})
.join('\r\n');
const data = [headerRow].concat(detailRows);
const result = data.join('\r\n');
return result;
}
Example #27
Source File: grid-body.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
GridBody: React.FC<GridBodyProps> = ({
tasks: originTasks,
dates,
barTasks: tasks,
rowHeight,
svgWidth,
columnWidth,
todayColor,
selectedTask,
ganttHeight,
setSelectedTask,
rtl,
onDateChange,
ganttEvent,
setRangeAddTime,
horizontalRange,
displayWidth,
onMouseMove: propsOnMouseMove,
mouseUnFocus: propsMouseUnFocus,
mousePos,
}) => {
let y = 0;
const gridRows: ReactChild[] = [];
const today = new Date();
const dateDelta =
dates[1].getTime() -
dates[0].getTime() -
dates[1].getTimezoneOffset() * 60 * 1000 +
dates[0].getTimezoneOffset() * 60 * 1000;
const [startPos, setStartPos] = React.useState<null | number[]>(null);
const [endPos, setEndPos] = React.useState<null | number[]>(null);
const [chosenTask, setChosenTask] = React.useState<Obj | null>(null);
React.useEffect(() => {
if (startPos && endPos) {
setRangeAddTime({ x1: startPos[0], x2: endPos[0] });
} else {
setRangeAddTime(null);
}
}, [startPos, endPos]);
const onMouseDown = (e: React.MouseEvent) => {
const gridPos = e.currentTarget.getBoundingClientRect();
const clickY = e.clientY - gridPos.y;
const clickPos = Math.floor(clickY / rowHeight);
const curTask = tasks[clickPos];
if (!curTask.start || !curTask.end) {
setSelectedTask(curTask.id);
setChosenTask(curTask);
setStartPos([
Math.floor((e.clientX - gridPos.x) / columnWidth) * columnWidth,
clickPos * rowHeight + 8,
e.clientX - gridPos.x,
]);
}
};
const mouseUnFocus = () => {
propsMouseUnFocus();
setStartPos(null);
setEndPos(null);
setChosenTask(null);
};
const curDates = dates.slice(...horizontalRange);
const todayIndex = findIndex(curDates, (item) => moment(item).isSame(today, 'day'));
const addTime = getDateFormX(startPos?.[0], endPos?.[0], dateDelta, columnWidth, curDates[0]?.getTime());
const onMouseUp = () => {
if (addTime.length && addTime[1] - addTime[0] >= dateDelta * 0.6 && chosenTask) {
onDateChange({ ...chosenTask, start: new Date(addTime[0]), end: new Date(addTime[1]) });
}
mouseUnFocus();
};
const onMouseMove = (e: React.MouseEvent) => {
const gridPos = e.currentTarget.getBoundingClientRect();
propsOnMouseMove(e);
const curEndPod = e.clientX - gridPos.x;
if (startPos) {
setEndPos(
curEndPod - startPos[2] > 10
? [
(Math.floor((e.clientX - gridPos.x + 1) / columnWidth) + 1) * columnWidth,
startPos[1] + rowHeight - 16,
curEndPod,
]
: null,
);
}
};
tasks?.forEach((task: Task, idx: number) => {
const validTask = task.start && task.end;
let PointIcon = null;
if (validTask) {
const displayPos = Math.floor(displayWidth / columnWidth);
if (curDates?.[0] && task.end < curDates[0]) {
PointIcon = (
<div className="text-default-2 hover:text-default-4 erda-gantt-grid-arrow-box flex items-center">
<ErdaIcon className="cursor-pointer " type="zuo" size={20} onClick={() => setSelectedTask(task.id)} />
<div className="erda-gantt-grid-arrow text-default-6">
{moment(task.start).format('MM-DD')} ~ {moment(task.end).format('MM-DD')}
</div>
</div>
);
} else if (curDates?.[displayPos] && task.start > curDates[displayPos]) {
PointIcon = (
<div
className="text-default-2 hover:text-default-4 erda-gantt-grid-arrow-box flex items-center"
style={{ marginLeft: displayWidth - 20 - 80 }}
>
<div className="erda-gantt-grid-arrow text-default-6">
{moment(task.start).format('MM-DD')} ~ {moment(task.end).format('MM-DD')}
</div>
<ErdaIcon className="cursor-pointer" onClick={() => setSelectedTask(task.id)} type="you" size={20} />
</div>
);
}
}
gridRows.push(
<foreignObject key={`Row${task.id}`} x="0" y={y} width={svgWidth} height={rowHeight}>
<div
className={`flex erda-gantt-grid-row h-full ${
selectedTask?.id === task.id ? 'erda-gantt-grid-row-selected' : ''
} ${!validTask ? 'on-add' : ''} ${mousePos?.[1] === idx ? 'on-hover' : ''}`}
/>
</foreignObject>,
);
y += rowHeight;
});
const { changedTask } = ganttEvent || {};
const realHeight = tasks.length * rowHeight;
const getAddRangePos = () => {
if (startPos && endPos) {
return {
transform: `translate(${min([startPos[0], endPos[0]])},${min([startPos[1], endPos[1]])})`,
width: Math.abs(startPos[0] - endPos[0]),
height: Math.abs(startPos[1] - endPos[1]),
};
}
return null;
};
const getRangePos = () => {
if (changedTask) {
return {
transform: `translate(${changedTask.x1},0)`,
width: changedTask.x2 - changedTask.x1,
height: max([ganttHeight, realHeight]),
};
} else if (startPos && endPos) {
return {
transform: `translate(${min([startPos[0], endPos[0]])},0)`,
width: Math.abs(endPos[0] - startPos[0]),
height: max([ganttHeight, realHeight]),
};
}
return null;
};
const getMouseBlockPos = () => {
if (mousePos) {
const curTask = tasks[mousePos[1]];
if (curTask && !curTask.start && !curTask.end) {
return {
width: columnWidth,
height: rowHeight - 16,
transform: `translate(${mousePos[0] * columnWidth},${mousePos[1] * rowHeight + 8})`,
};
}
}
return null;
};
const getMouseHoverPos = () => {
if (mousePos) {
return {
width: 8,
height: max([ganttHeight, realHeight]),
transform: `translate(${mousePos[0] * columnWidth + columnWidth / 2 - 4},0)`,
};
}
return null;
};
const rangePos = getRangePos();
const mouseBlockPos = getMouseBlockPos();
const addRangePos = getAddRangePos();
const mouseHoverPos = getMouseHoverPos();
const todayStartPos = todayIndex * columnWidth + columnWidth / 2 - 1;
return (
<g
className="gridBody"
onMouseDown={onMouseDown}
onMouseUp={() => {
onMouseUp();
}}
onMouseMove={onMouseMove}
onMouseLeave={mouseUnFocus}
>
{rangePos ? (
<rect {...rangePos} className="erda-gantt-grid-changed-range" />
) : mouseHoverPos ? (
<foreignObject {...mouseHoverPos}>
<div className="h-full w-full erda-gantt-grid-hover-box">
<div className="erda-gantt-grid-hover-arrow" />
<div className="erda-gantt-grid-hover-range h-full w-full" />
</div>
</foreignObject>
) : null}
<g className="rows">{gridRows}</g>
{addRangePos ? (
<g>
<foreignObject {...addRangePos}>
<div className="erda-gantt-grid-add-rect text-sm text-desc bg-white bg-opacity-100 w-full h-full">{`${moment(
addTime[0],
).format('MM-DD')}~${moment(addTime[1]).format('MM-DD')}`}</div>
</foreignObject>
</g>
) : mouseBlockPos ? (
<g>
<foreignObject {...mouseBlockPos}>
<div className="erda-gantt-grid-add-rect bg-white bg-opacity-100 w-full h-full" />
</foreignObject>
</g>
) : null}
{todayIndex > -1 ? (
<polyline
points={`${todayStartPos + columnWidth / 2},4 ${todayStartPos + columnWidth / 2},${max([
ganttHeight,
realHeight,
])}`}
className="erda-gantt-grid-today"
/>
) : null}
</g>
);
}
Example #28
Source File: tiled-filter-comp.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
TiledFilter = (props: IProps) => {
const { fields, delay = 1000, value: propsValue, onChange, expand: propsExpand = true } = props;
const [expand, setExpand] = React.useState(propsExpand);
const [value, setValue] = React.useState(propsValue || {});
const [labelWidth, setLabelWidth] = React.useState<string | number>('auto');
useMount(() => {
const labelEles = document.querySelectorAll('.tiled-fields-item-label');
const maxWidth: number = max(map(labelEles, (ele: HTMLSpanElement) => ele.offsetWidth));
setLabelWidth(Math.min(maxWidth, MAX_LABEL_WIDTH));
});
useUpdateEffect(() => {
setValue(propsValue || {});
}, [propsValue]);
React.useEffect(() => {
setExpand(propsExpand);
}, [propsExpand]);
const debouncedChange = React.useRef(debounce(onChange, delay));
const debouncedInputChange = React.useRef(debounce(onChange, 1000));
const inputFields: IField[] = [];
const selectFields: IField[] = [];
fields.forEach((field) => {
if (field.type === 'input') {
inputFields.push(field);
} else if (field.type.includes('select')) {
selectFields.push(field);
}
});
const onChangeItem = (val: string, field: IField, forceUpdate?: boolean) => {
if (forceUpdate) {
setValue((prevV) => {
const newVal = { ...prevV, [field.key]: val };
debouncedChange.current(newVal, { [field.key]: val });
return { ...prevV, [field.key]: val };
});
return;
}
const curValue = value[field.key];
if (field.multiple) {
setValue((prevV) => {
const curChangeVal = curValue?.includes(val)
? curValue.filter((vItem: string) => vItem !== val)
: (curValue || []).concat(val);
const newVal = { ...prevV, [field.key]: curChangeVal };
debouncedChange.current(newVal, { [field.key]: curChangeVal });
return newVal;
});
} else {
setValue((prevV) => {
const curChangeVal = curValue === val ? undefined : val;
const newVal = { ...prevV, [field.key]: curChangeVal };
debouncedChange.current(newVal, { [field.key]: curChangeVal });
return newVal;
});
}
};
const onChangeInputItem = (val: string, field: IField) => {
setValue((prevV) => {
const newVal = { ...prevV, [field.key]: val };
debouncedInputChange.current(newVal, { [field.key]: val });
return newVal;
});
};
const clearSelect = () => {
const newVal = {};
selectFields.forEach((sItem) => {
newVal[sItem.key] = undefined;
});
setValue((prev) => {
debouncedChange.current({ ...prev, ...newVal }, { ...newVal });
return { ...prev, ...newVal };
});
};
const getValueLength = () => {
let valLength = 0;
selectFields.forEach((sItem) => {
const curVal = value[sItem.key];
if (Array.isArray(curVal)) {
valLength += curVal.length;
} else if (curVal !== undefined && curVal !== '') {
valLength += 1;
}
});
return valLength;
};
const curValLength = getValueLength();
return (
<div className="tiled-filter">
<div className={`tiled-fields ${expand ? '' : 'no-expand'}`}>
{selectFields.map((item) => {
return (
<SelectFieldItem
key={item.key}
field={item}
value={value?.[item.key]}
onChangeItem={onChangeItem}
labelWidth={labelWidth}
/>
);
})}
</div>
<div className="flex justify-between items-center">
<div className="flex items-center">
{curValLength ? (
<>
<span>{`${i18n.t('{name} items selected', { name: curValLength })}`}</span>
<span className="fake-link ml-2 mr-4" onClick={clearSelect}>
{i18n.t('common:Clear selected')}
</span>
</>
) : null}
<div className="tiled-input">
{inputFields.map((inputItem) => {
return (
<Input
className={'tiled-input-item'}
key={inputItem.key}
value={value[inputItem.key]}
size="small"
allowClear
prefix={<ErdaIcon type="search1" size="16" />}
placeholder={inputItem.placeholder || i18n.t('press enter to search')}
onChange={(e) => onChangeInputItem(e.target.value, inputItem)}
/>
);
})}
</div>
</div>
<div className={`flex items-center expand-area`} onClick={() => setExpand(!expand)}>
<span className="mr-2">{expand ? i18n.t('fold') : i18n.t('expand')}</span>
<ErdaIcon type="down" className={`expand-icon flex items-center ${expand ? 'expand' : ''}`} size="16" />
</div>
</div>
</div>
);
}
Example #29
Source File: corner-cell.ts From S2 with MIT License | 4 votes |
protected drawCellText() {
const { x } = this.getContentArea();
const { y, height } = this.getCellArea();
const textStyle = this.getTextStyle();
const cornerText = this.getCornerText();
// 当为树状结构下需要计算文本前收起展开的icon占的位置
const maxWidth = this.getMaxTextWidth();
const emptyPlaceholder = getEmptyPlaceholder(
this.meta,
this.spreadsheet.options.placeholder,
);
const text = getEllipsisText({
text: cornerText,
maxWidth,
fontParam: textStyle,
placeholder: emptyPlaceholder,
});
this.actualText = text;
const ellipseIndex = text.indexOf('...');
let firstLine = text;
let secondLine = '';
// 存在文字的省略号 & 展示为tree结构
if (ellipseIndex !== -1 && this.spreadsheet.isHierarchyTreeType()) {
// 剪裁到 ... 最有点的后1个像素位置
const lastIndex = ellipseIndex + (isIPhoneX() ? 1 : 0);
firstLine = cornerText.substr(0, lastIndex);
secondLine = cornerText.slice(lastIndex);
// 第二行重新计算...逻辑
secondLine = getEllipsisText({
text: secondLine,
maxWidth,
fontParam: textStyle,
});
}
const { x: textX } = getTextPosition(
{
x: x + this.getTreeIconWidth(),
y,
width: maxWidth,
height,
},
textStyle,
);
const textY = y + (isEmpty(secondLine) ? height / 2 : height / 4);
// first line
this.textShapes.push(
renderText(
this,
[this.textShapes[0]],
textX,
textY,
firstLine,
textStyle,
),
);
// second line
if (!isEmpty(secondLine)) {
this.textShapes.push(
renderText(
this,
[this.textShapes[1]],
textX,
y + height * 0.75,
secondLine,
textStyle,
),
);
}
this.actualTextWidth = max([
measureTextWidth(firstLine, textStyle),
measureTextWidth(secondLine, textStyle),
]);
}