mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-04 11:52:07 +08:00
fix: 图表展示 bugifx & 优化
This commit is contained in:
@@ -46,30 +46,42 @@ export const supplementaryPoints = (
|
||||
extraCallback?: (point: [number, 0]) => any[]
|
||||
) => {
|
||||
lines.forEach(({ data }) => {
|
||||
// 获取未补点前线条的点的个数
|
||||
let len = data.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const timestamp = data[i][0] as number;
|
||||
// 数组第一个点和最后一个点单独处理
|
||||
// 记录当前处理到的点的下标值
|
||||
let i = 0;
|
||||
|
||||
for (; i < len; i++) {
|
||||
if (i === 0) {
|
||||
let firstPointTimestamp = data[0][0] as number;
|
||||
while (firstPointTimestamp - interval > timeRange[0]) {
|
||||
const prePointTimestamp = firstPointTimestamp - interval;
|
||||
data.unshift(extraCallback ? extraCallback([prePointTimestamp, 0]) : [prePointTimestamp, 0]);
|
||||
const prevPointTimestamp = firstPointTimestamp - interval;
|
||||
data.unshift(extraCallback ? extraCallback([prevPointTimestamp, 0]) : [prevPointTimestamp, 0]);
|
||||
firstPointTimestamp = prevPointTimestamp;
|
||||
len++;
|
||||
i++;
|
||||
firstPointTimestamp = prePointTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
if (i === len - 1) {
|
||||
let lastPointTimestamp = data[len - 1][0] as number;
|
||||
let lastPointTimestamp = data[i][0] as number;
|
||||
while (lastPointTimestamp + interval < timeRange[1]) {
|
||||
const next = lastPointTimestamp + interval;
|
||||
data.push(extraCallback ? extraCallback([next, 0]) : [next, 0]);
|
||||
lastPointTimestamp = next;
|
||||
const nextPointTimestamp = lastPointTimestamp + interval;
|
||||
data.push(extraCallback ? extraCallback([nextPointTimestamp, 0]) : [nextPointTimestamp, 0]);
|
||||
lastPointTimestamp = nextPointTimestamp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
let timestamp = data[i][0] as number;
|
||||
while (timestamp + interval < data[i + 1][0]) {
|
||||
const nextPointTimestamp = timestamp + interval;
|
||||
data.splice(i + 1, 0, extraCallback ? extraCallback([nextPointTimestamp, 0]) : [nextPointTimestamp, 0]);
|
||||
timestamp = nextPointTimestamp;
|
||||
len++;
|
||||
i++;
|
||||
}
|
||||
} else if (timestamp + interval < data[i + 1][0]) {
|
||||
data.splice(i + 1, 0, extraCallback ? extraCallback([timestamp + interval, 0]) : [timestamp + interval, 0]);
|
||||
len++;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -135,18 +147,37 @@ export const formatChartData = (
|
||||
};
|
||||
|
||||
const seriesCallback = (lines: { name: string; data: [number, string | number][] }[]) => {
|
||||
const len = CHART_COLOR_LIST.length;
|
||||
// series 配置
|
||||
return lines.map((line) => {
|
||||
return lines.map((line, i) => {
|
||||
return {
|
||||
...line,
|
||||
lineStyle: {
|
||||
width: 1.5,
|
||||
},
|
||||
connectNulls: false,
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 4,
|
||||
smooth: 0.25,
|
||||
areaStyle: {
|
||||
opacity: 0.02,
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: CHART_COLOR_LIST[i % len] + '10',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(255,255,255,0)', // 100% 处的颜色
|
||||
},
|
||||
],
|
||||
global: false, // 缺省为 false
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -189,6 +220,7 @@ export const getDetailChartConfig = (title: string, sliderPos: readonly [number,
|
||||
startValue: sliderPos[0],
|
||||
endValue: sliderPos[1],
|
||||
zoomOnMouseWheel: false,
|
||||
minValueSpan: 10 * 60 * 1000,
|
||||
},
|
||||
{
|
||||
start: 0,
|
||||
|
||||
@@ -63,56 +63,63 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-detail-modal-container {
|
||||
position: relative;
|
||||
.expand-icon-box {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 14px;
|
||||
right: 44px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s ease;
|
||||
.expand-icon {
|
||||
color: #adb5bc;
|
||||
line-height: 24px;
|
||||
}
|
||||
&:hover {
|
||||
background: rgba(33, 37, 41, 0.04);
|
||||
.expand-icon {
|
||||
color: #74788d;
|
||||
.overview-chart-detail-drawer {
|
||||
.dcloud-spin-nested-loading > div > .dcloud-spin.dcloud-spin-spinning {
|
||||
height: 300px;
|
||||
}
|
||||
&.dcloud-drawer .dcloud-drawer-body {
|
||||
padding: 0 20px;
|
||||
}
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
font-weight: normal;
|
||||
.title {
|
||||
font-family: @font-family-bold;
|
||||
font-size: 18px;
|
||||
color: #495057;
|
||||
letter-spacing: 0;
|
||||
.unit {
|
||||
font-family: @font-family-bold;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
.slider-info {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
font-family: @font-family;
|
||||
color: #303a51;
|
||||
}
|
||||
}
|
||||
.detail-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.title {
|
||||
font-family: @font-family-bold;
|
||||
font-size: 18px;
|
||||
color: #495057;
|
||||
letter-spacing: 0;
|
||||
.unit {
|
||||
font-family: @font-family-bold;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.5px;
|
||||
.chart-detail-modal-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.expand-icon-box {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 14px;
|
||||
right: 44px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s ease;
|
||||
.expand-icon {
|
||||
color: #adb5bc;
|
||||
line-height: 24px;
|
||||
}
|
||||
&:hover {
|
||||
background: rgba(33, 37, 41, 0.04);
|
||||
.expand-icon {
|
||||
color: #74788d;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.detail-table {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
.detail-table {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,8 +216,8 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
onChange={ksHeaderChange}
|
||||
nodeScopeModule={{
|
||||
customScopeList: scopeList,
|
||||
scopeName: `自定义 ${dashboardType === MetricType.Broker ? 'Broker' : 'Topic'} 范围`,
|
||||
showSearch: dashboardType === MetricType.Topic,
|
||||
scopeName: dashboardType === MetricType.Broker ? 'Broker' : 'Topic',
|
||||
scopeLabel: `自定义 ${dashboardType === MetricType.Broker ? 'Broker' : 'Topic'} 范围`,
|
||||
}}
|
||||
indicatorSelectModule={{
|
||||
hide: false,
|
||||
|
||||
@@ -26,8 +26,8 @@ const OptionsDefault = [
|
||||
const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
const {
|
||||
customScopeList: customList,
|
||||
scopeName = '自定义节点范围',
|
||||
showSearch = false,
|
||||
scopeName = '',
|
||||
scopeLabel = '自定义范围',
|
||||
searchPlaceholder = '输入内容进行搜索',
|
||||
} = nodeScopeModule;
|
||||
const [topNum, setTopNum] = useState<number>(5);
|
||||
@@ -70,7 +70,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
change(checkedListTemp, false);
|
||||
setIsTop(false);
|
||||
setTopNum(null);
|
||||
setInputValue(`已选${checkedListTemp?.length}项`);
|
||||
setInputValue(`${checkedListTemp?.length}项`);
|
||||
setPopVisible(false);
|
||||
}
|
||||
};
|
||||
@@ -109,7 +109,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
{/* <span>时间:</span> */}
|
||||
<div className="flx_con">
|
||||
<div className="flx_l">
|
||||
<h6 className="time_title">选择top范围</h6>
|
||||
<h6 className="time_title">选择 top 范围</h6>
|
||||
<Radio.Group
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
@@ -128,7 +128,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
</Radio.Group>
|
||||
</div>
|
||||
<div className="flx_r">
|
||||
<h6 className="time_title">{scopeName}</h6>
|
||||
<h6 className="time_title">{scopeLabel}</h6>
|
||||
<div className="custom-scope">
|
||||
<div className="check-row">
|
||||
<Checkbox className="check-all" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
|
||||
@@ -136,9 +136,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
</Checkbox>
|
||||
<Input
|
||||
className="search-input"
|
||||
suffix={
|
||||
<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />
|
||||
}
|
||||
suffix={<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />}
|
||||
size="small"
|
||||
placeholder={searchPlaceholder}
|
||||
onChange={(e) => setScopeSearchValue(e.target.value)}
|
||||
@@ -148,7 +146,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
<Checkbox.Group style={{ width: '100%' }} onChange={checkChange} value={checkedListTemp}>
|
||||
<Row gutter={[10, 12]}>
|
||||
{customList
|
||||
.filter((item) => !showSearch || item.label.includes(scopeSearchValue))
|
||||
.filter((item) => item.label.includes(scopeSearchValue))
|
||||
.map((item) => (
|
||||
<Col span={12} key={item.value}>
|
||||
<Checkbox value={item.value}>{item.label}</Checkbox>
|
||||
@@ -180,6 +178,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
return (
|
||||
<>
|
||||
<div id="d-node-scope">
|
||||
<div className="scope-title">{scopeName}筛选:</div>
|
||||
<Popover
|
||||
trigger={['click']}
|
||||
visible={popVisible}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Tooltip, Select, IconFont, Utils, Divider } from 'knowdesign';
|
||||
import { Tooltip, Select, IconFont, Utils, Divider, Button } from 'knowdesign';
|
||||
import moment from 'moment';
|
||||
import { DRangeTime } from 'knowdesign';
|
||||
import IndicatorDrawer from './IndicatorDrawer';
|
||||
@@ -48,7 +48,7 @@ export interface IcustomScope {
|
||||
export interface InodeScopeModule {
|
||||
customScopeList: IcustomScope[];
|
||||
scopeName?: string;
|
||||
showSearch?: boolean;
|
||||
scopeLabel?: string;
|
||||
searchPlaceholder?: string;
|
||||
change?: () => void;
|
||||
}
|
||||
@@ -138,9 +138,13 @@ const SingleChartHeader = ({
|
||||
};
|
||||
|
||||
const reloadRangeTime = () => {
|
||||
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
||||
const curTimeStamp = moment().valueOf();
|
||||
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
||||
if (isRelativeRangeTime) {
|
||||
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
||||
const curTimeStamp = moment().valueOf();
|
||||
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
||||
} else {
|
||||
setRangeTime([...rangeTime]);
|
||||
}
|
||||
};
|
||||
|
||||
const openIndicatorDrawer = () => {
|
||||
@@ -174,12 +178,10 @@ const SingleChartHeader = ({
|
||||
{!hideGridSelect && (
|
||||
<Select className="grid-select" style={{ width: 70 }} value={gridNum} options={GRID_SIZE_OPTIONS} onChange={sizeChange} />
|
||||
)}
|
||||
<Divider type="vertical" style={{ height: 20, top: 0 }} />
|
||||
<Tooltip title="点击指标筛选,可选择指标" placement="bottomRight">
|
||||
<div className="icon-box" onClick={openIndicatorDrawer}>
|
||||
<IconFont className="icon" type="icon-shezhi1" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
{(!hideNodeScope || !hideGridSelect) && <Divider type="vertical" style={{ height: 20, top: 0 }} />}
|
||||
<Button type="primary" onClick={openIndicatorDrawer}>
|
||||
指标筛选
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
@import '~knowdesign/es/basic/style/mixins/index';
|
||||
|
||||
#d-node-scope {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
.scope-title {
|
||||
font-size: 14px;
|
||||
color: #74788d;
|
||||
}
|
||||
.input-span {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -29,10 +34,10 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
&.relativeTime {
|
||||
width: 160px;
|
||||
width: 200px;
|
||||
}
|
||||
&.absoluteTime {
|
||||
width: 300px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
Reference in New Issue
Block a user