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]} /> } ); } }