import React from 'react';
import {
AreaChart,
Area,
ComposedChart,
Line,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
ReferenceLine,
CartesianGrid,
Label,
} from 'recharts';
import { Checkbox } from 'UI';
import { durationFromMsFormatted } from 'App/date';
import { formatBytes } from 'App/utils';
const tooltipWrapperClass = "bg-white rounded border px-2 py-1";
const CPU_VISUAL_OFFSET = 10;
const FPS_COLOR = '#C5E5E7';
const FPS_STROKE_COLOR = "#92C7CA";
const FPS_LOW_COLOR = "pink";
const FPS_VERY_LOW_COLOR = "red";
const CPU_COLOR = "#A8D1DE";
const CPU_STROKE_COLOR = "#69A5B8";
const BATTERY_COLOR = "orange";
const BATTERY_STROKE_COLOR = "orange";
const USED_HEAP_COLOR = '#A9ABDC';
const USED_HEAP_STROKE_COLOR = "#8588CF";
const TOTAL_HEAP_STROKE_COLOR = '#4A4EB7';
const NODES_COUNT_COLOR = "#C6A9DC";
const NODES_COUNT_STROKE_COLOR = "#7360AC";
const HIDDEN_SCREEN_COLOR = "#CCC";
const CURSOR_COLOR = "#394EFF";
const Gradient = ({ color, id }) => (
);
const TOTAL_HEAP = "Allocated Heap";
const USED_HEAP = "JS Heap";
const FPS = "Framerate";
const CPU = "CPU Load";
const MEMORY = "Memory Usage";
const BATTERY = "Battery Charge";
const NODES_COUNT = "Nodes Сount";
const FPSTooltip = ({ active, payload }) => {
if (!active || payload.length < 3) {
return null;
}
if (payload[0].value === null) {
return (
{"Page is not active. User switched the tab or hid the window."}
);
}
let style;
if (payload[1].value != null && payload[1].value > 0) {
style = { color: FPS_LOW_COLOR };
}
if (payload[2].value != null && payload[2].value > 0) {
style = { color: FPS_VERY_LOW_COLOR };
}
return (
{`${ FPS }: `}
{ Math.trunc(payload[0].value) }
);
};
const CPUTooltip = ({ active, payload }) => {
if (!active || payload.length < 1 || payload[0].value === null) {
return null;
}
return (
{`${ CPU }: `}
{ payload[0].value - CPU_VISUAL_OFFSET }
{"%"}
);
};
const HeapTooltip = ({ active, payload }) => {
if (!active || payload.length < 2) return null;
return (
{`${ TOTAL_HEAP }: `}
{ formatBytes(payload[0].value)}
{`${ USED_HEAP }: `}
{ formatBytes(payload[1].value)}
);
}
const MemoryTooltip = ({ active, payload}) => {
if (!active || payload.length < 1) return null;
return (
{`${ MEMORY }: `}
{ formatBytes(payload[0].value)}
);
}
const BatteryTooltip = ({ active, payload}) => {
if (!active || payload.length < 1 || payload[0].value === null) {
return null;
}
return (
{`${ BATTERY }: `}
{ payload[0].value }
{"%"}
);
}
const NodesCountTooltip = ({ active, payload } ) => {
if (!active || payload.length === 0) return null;
return (
{`${ NODES_COUNT }: `}
{ payload[0].value }
);
}
const TICKS_COUNT = 10;
function generateTicks(data: Array): Array {
if (data.length === 0) return [];
const minTime = data[0].time;
const maxTime = data[data.length-1].time;
const ticks = [];
const tickGap = (maxTime - minTime) / (TICKS_COUNT + 1);
for (let i = 0; i < TICKS_COUNT; i++) {
const tick = tickGap * (i + 1) + minTime;
ticks.push(tick);
}
return ticks;
}
const LOW_FPS = 30;
const VERY_LOW_FPS = 20;
const LOW_FPS_MARKER_VALUE = 5;
const HIDDEN_SCREEN_MARKER_VALUE = 20;
function adaptForGraphics(data) {
return data.map((point, i) => {
let fpsVeryLowMarker = null;
let fpsLowMarker = null;
let hiddenScreenMarker = 0;
if (point.fps != null) {
fpsVeryLowMarker = 0;
fpsLowMarker = 0;
if (point.fps < VERY_LOW_FPS) {
fpsVeryLowMarker = LOW_FPS_MARKER_VALUE;
} else if (point.fps < LOW_FPS) {
fpsLowMarker = LOW_FPS_MARKER_VALUE;
}
}
if (point.fps == null ||
(i > 0 && data[i - 1].fps == null) //||
//(i < data.length-1 && data[i + 1].fps == null)
) {
hiddenScreenMarker = HIDDEN_SCREEN_MARKER_VALUE;
}
if (point.cpu != null) {
point.cpu += CPU_VISUAL_OFFSET;
}
return {
...point,
fpsLowMarker,
fpsVeryLowMarker,
hiddenScreenMarker,
}
});
}
export default class Performance extends React.PureComponent {
_timeTicks = generateTicks(this.props.performanceChartData)
_data = adaptForGraphics(this.props.performanceChartData)
onDotClick = ({ index }) => {
const point = this._data[index];
if (!!point) {
this.props.player.jump(point.time);
}
}
onChartClick = (e) => {
if (e === null) return;
const { activeTooltipIndex } = e;
const point = this._data[activeTooltipIndex];
if (!!point) {
this.props.player.jump(point.time);
}
}
render() {
const {
performanceChartTime,
avaliability = {},
hiddenScreenMarker = true,
} = this.props;
const { fps, cpu, heap, nodes, memory, battery } = avaliability;
const avaliableCount = [ fps, cpu, heap, nodes, memory, battery ].reduce((c, av) => av ? c + 1 : c, 0);
const height = avaliableCount === 0 ? "0" : `${100 / avaliableCount}%`;
return (
<>
{ fps &&
{/* */}
{/* */}
{/* */}
{ hiddenScreenMarker &&
}
{/* */}
}
{ cpu &&
{/* */}
""}
domain={[0, 'dataMax']}
ticks={this._timeTicks}
>
{ hiddenScreenMarker &&
}
}
{ battery &&
{/* */}
""}
domain={[0, 'dataMax']}
ticks={this._timeTicks}
>
}
{ memory &&
{/* */}
""}
domain={[0, 'dataMax']}
ticks={this._timeTicks}
>
max*1.2]}
/>
}
{ heap &&
{/* */}
""} // tick={false} + this._timeTicks to cartesian array
domain={[0, 'dataMax']}
ticks={this._timeTicks}
>
max*1.2]}
/>
}
{ nodes &&
{/* */}
""}
domain={[0, 'dataMax']}
ticks={this._timeTicks}
>
max*1.2]}
/>
}
>
);
}
}