Add statistics panel

This commit is contained in:
MrKBear 2022-05-26 17:08:04 +08:00
parent 2dbbd0952a
commit 4ea3c9e1f4

View File

@ -3,15 +3,17 @@ import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
import { useSettingWithEvent, IMixinSettingProps, Themes } from "@Context/Setting"; import { useSettingWithEvent, IMixinSettingProps, Themes } from "@Context/Setting";
import { import {
Chart as ChartJS, CategoryScale, LinearScale, Chart as ChartJS, CategoryScale, LinearScale,
BarElement, Tooltip, Legend BarElement, Tooltip, Legend, Decimation,
PointElement, LineElement, Title
} from 'chart.js'; } from 'chart.js';
import { Bar } from 'react-chartjs-2'; import { Bar, Line } from 'react-chartjs-2';
import { Theme } from "@Component/Theme/Theme"; import { Theme } from "@Component/Theme/Theme";
import { Icon } from "@fluentui/react"; import { Icon } from "@fluentui/react";
import { Model } from "@Model/Model"; import { Model } from "@Model/Model";
import { Group } from "@Model/Group"; import { Group } from "@Model/Group";
import { ActuatorModel } from "@Model/Actuator"; import { ActuatorModel } from "@Model/Actuator";
import { Message } from "@Input/Message/Message"; import { Message } from "@Input/Message/Message";
import { Clip, IFrame } from "@Model/Clip";
import "./Statistics.scss"; import "./Statistics.scss";
ChartJS.register( ChartJS.register(
@ -19,19 +21,19 @@ ChartJS.register(
LinearScale, LinearScale,
BarElement, BarElement,
Tooltip, Tooltip,
Legend Legend,
PointElement,
LineElement,
Title,
Decimation
); );
enum ChartType {
}
interface IStatisticsProps { interface IStatisticsProps {
} }
@useSettingWithEvent("themes", "language", "lineChartType") @useSettingWithEvent("themes", "language", "lineChartType")
@useStatusWithEvent("focusClipChange", "actuatorStartChange", "fileLoad", "modelUpdate", "individualChange") @useStatusWithEvent("focusClipChange", "actuatorStartChange", "fileLoad", "modelUpdate", "recordLoop", "individualChange")
class Statistics extends Component<IStatisticsProps & IMixinStatusProps & IMixinSettingProps> { class Statistics extends Component<IStatisticsProps & IMixinStatusProps & IMixinSettingProps> {
public barDarkOption = { public barDarkOption = {
@ -85,13 +87,121 @@ class Statistics extends Component<IStatisticsProps & IMixinStatusProps & IMixin
/> />
} }
private clipBarChart(frame: IFrame, theme: boolean) {
const datasets: any[] = [];
const labels: any[] = ["Group"];
// 收集数据
frame.commands.forEach((command) => {
let label = command.name;
let color = `rgb(${command.parameter?.color.map((v: number) => Math.floor(v * 255)).join(",")})`;
if (command.type === "points") {
datasets.push({label, data: [(command.data?.length ?? 0) / 3], backgroundColor: color});
}
});
if (datasets.length <= 0) {
return <Message i18nKey="Panel.Info.Statistics.Nodata"/>
}
return <Bar
data={{datasets, labels}}
options={ theme ? this.barLightOption : this.barDarkOption }
/>
}
public lineDarkOption = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom' as const,
labels: { boxWidth: 10, boxHeight: 10, color: 'rgba(255, 255, 255, .5)' },
decimation: { enabled: true }
},
decimation: { enabled: true, algorithm: "lttb" as const, samples: 100 }
},
scales: {
x: { grid: { color: 'rgba(255, 255, 255, .2)' }, type: "linear", title: { color: 'rgba(255, 255, 255, .5)'} },
y: { grid: { color: 'rgba(255, 255, 255, .2)', borderDash: [3, 3] }, title: { color: 'rgba(255, 255, 255, .5)'} }
}
};
public lineLightOption = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom' as const,
labels: { boxWidth: 10, boxHeight: 10, color: 'rgba(0, 0, 0, .5)' },
},
decimation: { enabled: true, algorithm: "lttb" as const, samples: 100 }
},
scales: {
x: { grid: { color: 'rgba(0, 0, 0, .2)' }, title: { color: 'rgba(0, 0, 0, .5)'} },
y: { grid: { color: 'rgba(0, 0, 0, .2)', borderDash: [3, 3] }, title: { color: 'rgba(0, 0, 0, .5)'} }
}
};
private clipLineChart(clip: Clip, theme: boolean) {
type IDataSet = {label: string, data: number[], backgroundColor: string, id: string};
const datasets: IDataSet[] = [];
const labels: number[] = [];
// 收集数据
clip.frames.forEach((frame) => {
labels.push(frame.process);
frame.commands.forEach((command) => {
if (command.type !== "points") return;
let findKey: IDataSet | undefined;
for (let i = 0; i < datasets.length; i++) {
if (datasets[i].id === command.id) {
findKey = datasets[i];
break;
}
}
if (findKey) {
findKey.data.push((command.data?.length ?? 0) / 3);
} else {
findKey = {} as any;
findKey!.data = [(command.data?.length ?? 0) / 3];
findKey!.label = command.name ?? "";
findKey!.backgroundColor = `rgb(${command.parameter?.color.map((v: number) => Math.floor(v * 255)).join(",")})`;
findKey!.id = command.id;
datasets.push(findKey!);
}
})
});
if (datasets.length <= 0) {
return <Message i18nKey="Panel.Info.Statistics.Nodata"/>
}
return <Line
options={ theme ? this.lineLightOption : this.lineDarkOption }
data={{labels, datasets:[{data: [1], }] }}
/>;
}
private renderChart() { private renderChart() {
let themes = this.props.setting?.themes === Themes.light; let themes = this.props.setting?.themes === Themes.light;
let lineChartType = this.props.setting?.lineChartType;
// 播放模式 // 播放模式
if (this.props.status?.focusClip) { if (this.props.status?.focusClip) {
return this.modelBarChart(this.props.status.model, themes); if (this.props.status.actuator.playClip && lineChartType) {
return this.clipLineChart(this.props.status.actuator.playClip, themes);
}
if (this.props.status.actuator.playFrame) {
return this.clipBarChart(this.props.status.actuator.playFrame, themes);
}
} }
// 正在录制中 // 正在录制中
@ -99,6 +209,9 @@ class Statistics extends Component<IStatisticsProps & IMixinStatusProps & IMixin
this.props.status?.actuator.mod === ActuatorModel.Record || this.props.status?.actuator.mod === ActuatorModel.Record ||
this.props.status?.actuator.mod === ActuatorModel.Offline this.props.status?.actuator.mod === ActuatorModel.Offline
) { ) {
if (this.props.status.actuator.recordClip && lineChartType) {
return this.clipLineChart(this.props.status.actuator.recordClip, themes);
}
return this.modelBarChart(this.props.status.model, themes); return this.modelBarChart(this.props.status.model, themes);
} }