Loading js-apps/meep-frontend/src/js/containers/dashboard-container.js→js-apps/meep-frontend/src/js/containers/exec/dashboard-container.js +69 −34 Original line number Diff line number Diff line Loading @@ -10,35 +10,35 @@ import { Slider } from '@rmwc/slider'; import moment from 'moment'; import * as d3 from 'd3'; import { blue } from './graph-utils'; import { blue } from '../graph-utils'; import IDCLineChart from './idc-line-chart'; import IDCGraph from './idc-graph'; import IDCAppsView from './idc-apps-view'; import IDSelect from '../components/helper-components/id-select'; import IDCVis from './idc-vis'; import ResizeableContainer from './resizeable-container'; import IDCGraph from '../idc-graph'; import IDCAppsView from '../idc-apps-view'; import IDSelect from '../../components/helper-components/id-select'; import IDCVis from '../idc-vis'; import ResizeableContainer from '../resizeable-container'; import { getScenarioNodeChildren, isApp } from '../util/scenario-utils'; } from '../../util/scenario-utils'; import { isDataPointOfType } from '../util/metrics'; } from '../../util/metrics'; import { execFakeChangeSelectedDestination, execChangeSourceNodeSelected, execChangeMetricsTimeIntervalDuration, execClearMetricsEpochs } from '../state/exec'; } from '../../state/exec'; import { uiExecChangeDashboardView1, uiExecChangeDashboardView2, uiExecExpandDashboardConfig } from '../state/ui'; } from '../../state/ui'; import { Loading @@ -53,10 +53,34 @@ import { LATENCY_VIEW, THROUGHPUT_VIEW, VIS_VIEW } from '../meep-constants'; } from '../../meep-constants'; const TIME_FORMAT = moment.HTML5_FMT.DATETIME_LOCAL_MS; const MIN_TIME_RANGE_VALUE = 15; const MAX_TIME_RANGE_VALUE = 60; const greyColor = 'grey'; const styles = { button: { marginRight: 0 }, slider: { container: { marginTop:10, marginBottom: 10, color: greyColor }, boundaryValues: { marginTop: 15 }, title: { marginBottom: 0 } } }; function colorArray(dataLength) { const colorScale = d3.interpolateInferno; // Other possible color scales: Loading Loading @@ -116,22 +140,36 @@ const TimeIntervalConfig = (props) => { </Button> ); } return ( <div style={{marginTop: 10}}> <Grid> <GridCell span={3}> <div style={{margin:10}}> <div> <div style={styles.slider.container}> <div style={styles.slider.title}> <span className="mdc-typography--headline8">Timeframe in secs </span> </div> <Grid> <GridCell span={1} style={styles.slider.boundaryValues}> <span>{MIN_TIME_RANGE_VALUE}</span> </GridCell> <GridCell span={10}> <Slider value={props.value} onChange={e => props.timeIntervalDurationChanged(e.detail.value)} onChange={e => props.changeTimeIntervalDuration(e.detail.value)} discrete min={5} max={60} min={MIN_TIME_RANGE_VALUE} max={MAX_TIME_RANGE_VALUE} step={1} /> </GridCell> <GridCell span={1} style={styles.slider.boundaryValues}> <span>{MAX_TIME_RANGE_VALUE}</span> </GridCell> </Grid> </div> </GridCell> Loading Loading @@ -199,7 +237,7 @@ const ConfigurationView = (props) => { </GridCell> </Grid> <TimeIntervalConfig timeIntervalDurationChanged={(value) => {props.timeIntervalDurationChanged(value);}} changeTimeIntervalDuration={(value) => {props.changeTimeIntervalDuration(value);}} stopSlidingWindow={props.stopSlidingWindow} startSlidingWindow={props.startSlidingWindow} slidingWindowStopped={props.slidingWindowStopped} Loading @@ -208,10 +246,6 @@ const ConfigurationView = (props) => { ); }; const buttonStyles = { marginRight: 0 }; const ViewForName = ( { keyForSvg, Loading Loading @@ -365,7 +399,7 @@ const DashboardConfiguration = (props) => { changeSourceNodeSelected={props.changeSourceNodeSelected} changeDisplayEdgeLabels={props.changeDisplayEdgeLabels} displayEdgeLabels={props.displayEdgeLabels} timeIntervalDurationChanged={props.timeIntervalDurationChanged} changeTimeIntervalDuration={props.changeTimeIntervalDuration} stopSlidingWindow={props.stopSlidingWindow} startSlidingWindow={props.startSlidingWindow} slidingWindowStopped={props.slidingWindowStopped} Loading @@ -375,7 +409,7 @@ const DashboardConfiguration = (props) => { const buttonConfig = !props.dashboardConfigExpanded ? ( <Button outlined style={buttonStyles} onClick={() => props.expandDashboardConfig(true)}> <Button outlined style={styles.button} onClick={() => props.expandDashboardConfig(true)}> Open </Button> ) Loading @@ -383,7 +417,7 @@ const DashboardConfiguration = (props) => { const buttonClose = props.dashboardConfigExpanded ? ( <Button outlined style={buttonStyles} onClick={() => props.expandDashboardConfig(false)}> <Button outlined style={styles.button} onClick={() => props.expandDashboardConfig(false)}> Close </Button> ) Loading @@ -391,6 +425,7 @@ const DashboardConfiguration = (props) => { return ( <Elevation z={2} className="component-style" style={{padding: 10, marginBottom: 10}} > Loading Loading @@ -671,7 +706,7 @@ class DashboardContainer extends Component { nodeIds={appIds} sourceNodeSelected={this.props.sourceNodeSelected} changeSourceNodeSelected={(nodeId) => this.props.changeSourceNodeSelected(appMap[nodeId])} timeIntervalDurationChanged={(duration) => {this.changeMetricsTimeIntervalDuration(duration);}} changeTimeIntervalDuration={(duration) => {this.changeMetricsTimeIntervalDuration(duration);}} stopSlidingWindow={() => this.stopSlidingWindow()} startSlidingWindow={() => this.startSlidingWindow()} slidingWindowStopped={this.state.slidingWindowStopped} Loading @@ -685,8 +720,8 @@ class DashboardContainer extends Component { <Grid> {!view1Present ? null : ( <GridCell span={span1} style={{paddingRight: 10}} className='chartContainer'> <Elevation z={2} <GridCell span={span1} className='chartContainer'> <Elevation z={2} className="component-style" style={{padding: 10}} > {view1} Loading @@ -696,7 +731,7 @@ class DashboardContainer extends Component { {!view2Present ? null : ( <GridCell span={span2} style={{marginLeft: -10, paddingLeft: 10}} className='chartContainer'> <Elevation z={2} <Elevation z={2} className="component-style" style={{padding: 10}} > {view2} Loading js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import { connect } from 'react-redux'; import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import DashboardContainer from '../dashboard-container'; import DashboardContainer from './dashboard-container'; import ExecPageScenarioButtons from './exec-page-scenario-buttons'; import HeadlineBar from '../../components/headline-bar'; Loading js-apps/meep-frontend/src/js/containers/idc-line-chart.js→js-apps/meep-frontend/src/js/containers/exec/idc-line-chart.js +5 −4 Original line number Diff line number Diff line Loading @@ -19,8 +19,8 @@ import * as d3 from 'd3'; import React from 'react'; import uuid from 'uuid'; import {Axis, axisPropsFromTickScale, LEFT, BOTTOM} from 'react-d3-axis'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../meep-constants'; import { blue } from './graph-utils'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../../meep-constants'; import { blue } from '../graph-utils'; // const Axis = props => { // const axisRef = axis => { // axis && props.axisCreator(select(axis)); Loading @@ -32,10 +32,11 @@ import { blue } from './graph-utils'; const notNull = x => x; const IDCLineChart = (props) => { const keyForSvg=props.keyForSvg; let width = props.width; let yClipping = 45; const margin = {top: 20, right: 40, bottom: 30, left: 60}; let width = props.width - (margin.right + margin.left); let yClipping = 45; // const width = props.width; // - margin.left - margin.right; const height = props.height; // - margin.top - margin.bottom; Loading js-apps/meep-frontend/src/js/containers/idc-line-chart-back.jsdeleted 100644 → 0 +0 −234 Original line number Diff line number Diff line /* * Copyright (c) 2019 * InterDigital Communications, Inc. * All rights reserved. * * The information provided herein is the proprietary and confidential * information of InterDigital Communications, Inc. */ import _ from 'lodash'; import React, { useRef, useEffect } from 'react'; import * as d3 from 'd3'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../meep-constants'; const notNull = x => x; const IDCLineChartBack = props => { const d3Container = useRef(null); /* The useEffect Hook is for running side effects outside of React, for instance inserting elements into the DOM using D3 */ useEffect( () => { const margin = {top: 20, right: 40, bottom: 30, left: 60}; const width = props.width - margin.left - margin.right; const height = props.height - margin.top - margin.bottom; let mainGroup = d3.select(d3Container.current); if (mainGroup.select('g').size() === 0) { mainGroup = mainGroup.append('g') .attr('width', props.width + margin.left + margin.right) .attr('height', props.height + margin.top + margin.bottom) .attr('transform', `translate(${margin.left}, ${margin.top})`); } const flattenSeries = series => { return _.flatMap(Object.values(series)); }; const chart = (series) => { const destinations = props.selectedSource ? props.destinations.slice(-props.destinations.length) : []; const colorRange = destinations.map(s => props.colorForApp[s]); const yRange = [0, 200]; const timeRange = d3.extent(flattenSeries(series), d => new Date(d.timestamp)); const x = d3.scaleTime().domain(timeRange).range([0, width]); const y = d3.scaleLinear().domain(yRange).range([height - 50, 0]); const z = d3.scaleOrdinal().range(colorRange); // Axes const xAxis = d3.axisBottom(x); //.ticks(d3.timeSeconds); const yAxis = d3.axisLeft(y).scale(y) .tickSize(0.01); // const yAxisr = d3.axisLeft(y); // const dataLinePointFromDataPoint = key => point => { // if (point[key] === undefined) { // console.log('point[key] is undefined, for key ' + key + ' and point ', point); // return null; // } // return { // date: point.date, // value: point[key] // }; // }; const dataLineFromSeries = series => key => { const line = series[key].filter(notNull).filter(p => p.value); // .sort((a, b) => { // return x(new Date(a.timestamp)) - x(new Date(b.timestamp)); // }); //TODO: add point at props.startTime and props.endTime line.key = key; return line; }; let dataLines = destinations.map(dataLineFromSeries(props.series)); // TODO: remove dataLines = dataLines.length ? [dataLines[0]] : []; const valueLine = d3.line() .x(function(d) { return margin.left + x(new Date(d.timestamp)); }) .y(function(d) { return y(d.value) + margin.top; }) .curve(d3.curveMonotoneX); mainGroup.selectAll('.line') .data(dataLines) .join('path').attr('class', 'line') .attr('d', valueLine) .style('stroke', (d, i) => z(i)) .style('fill', 'none') .style('stroke-width', 3); // if (mainGroup.selectAll('.line').size() > 0) { // const linesMarginLeft = mainGroup.selectAll('.line').attr('margin-left'); // console.log('linesMarginLeft: ', linesMarginLeft); // } // Mobility events // const mobilityEventLine = d => `M${x(new Date(d.timestamp)) + margin.left},${y(yRange[0]) + margin.top} L${x(new Date(d.timestamp)) + margin.left},${y(yRange[1]) + margin.top}`; const mobilityEventLine = d => `M${x(new Date(d.timestamp)) + margin.left},${y(yRange[1]) + margin.top} L${x(new Date(d.timestamp)) + margin.left},${y(yRange[0]) + margin.top}`; mainGroup.selectAll('.mobilityEventLine') .data(props.mobilityEvents) .join('path') .attr('class', 'mobilityEventLine') .attr('d', mobilityEventLine) .attr('id', d => d.timestamp) .style('stroke', 'gray') .style('stroke-width', 1) .style('fill', 'none'); mainGroup.selectAll('.mobilityEventLineText') .data(props.mobilityEvents) .join('text') .attr('class', 'mobilityEventLineText') .style('stroke','gray') .style('stroke-width', 1) .style('fill','gray'); // .attr('x', d => x(new Date(d.timestamp)) + margin.left) // .attr('dy',50 + margin.top) mainGroup.selectAll('.mobilityEventLineTextPath').remove(); mainGroup.selectAll('.mobilityEventLineText') .data(props.mobilityEvents) .append('textPath') .attr('class', 'mobilityEventLineTextPath') .attr('xlink:href', d => `#${d.timestamp}`) .attr('stroke','gray') .attr('fill','gray') .text(d => `Mobility Event: ${d.src} to ${d.dest}`) .attr('transform', 'rotate(-180)'); const xAxisGroup = mainGroup.selectAll('.xaxis'); if (xAxisGroup.size() === 0) { mainGroup.append('g') .attr('class', 'xaxis') .attr('transform', 'translate(0,' + height + ')').call(xAxis); } else { xAxisGroup.attr('transform', 'translate(0,' + height + ')').call(xAxis); } mainGroup.selectAll('.xaxis').call(xAxis); const yAxisGroup = mainGroup.selectAll('.yaxis'); if (yAxisGroup.size() === 0) { mainGroup.append('g') .attr('class', 'yaxis') .attr('transform', 'translate(' + width + ', 0)') .style('z-index', '18') .call(yAxis); } else { yAxisGroup.attr('transform', 'translate(' + width + ', 0)'); } // text label for the y axis const labelForType = type => { switch (type) { case ME_LATENCY_METRICS: return 'Latency (ms)'; case ME_THROUGHPUT_METRICS: return 'Throughput (kbs)'; default: return ''; } }; const yAxisLabel = labelForType(props.dataType); if (!mainGroup.selectAll('.yLabel').size()) { mainGroup.append('text') .attr('class', 'yLabel') .attr('transform', 'rotate(-90)') .attr('y', 0 - margin.left + 10) .attr('x', 0 - (height / 2)) .attr('dy', '1em') .style('text-anchor', 'middle') .text(yAxisLabel); } else { mainGroup.selectAll('.yLabel') .text(yAxisLabel); } const yAxisGroup0 = mainGroup.selectAll('.yaxis0'); if (yAxisGroup0.size() === 0) { mainGroup.append('g') .attr('class', 'yaxis0') .attr('transform', 'translate(0, 0)') .style('z-index', '18') .call(yAxis); } else { yAxisGroup0.attr('transform', 'translate(0, 0)').style('z-index', '18'); } }; chart(props.series); }, /* useEffect has a dependency array (below). It's a list of dependency variables for this useEffect block. The block will run after mount and whenever any of these variables change. We still have to check if the variables are valid, but we do not have to compare old props to next props to decide whether to rerender. */ [props.data, d3Container.current]); return ( <div className='chart'> <svg //viewBox='0 -20 200 33' ref={d3Container} className='d3-component' height={props.height} width={props.width} > </svg> </div> ); }; export default IDCLineChartBack; No newline at end of file js-apps/meep-frontend/src/js/state/ui/index.js +3 −5 Original line number Diff line number Diff line Loading @@ -154,6 +154,9 @@ export { // Action types EXEC_CHANGE_CURRENT_EVENT, UI_EXEC_CHANGE_SHOW_DASHBOARD_CONFIG, UI_EXEC_CHANGE_DASHBOARD_VIEW1, UI_EXEC_CHANGE_DASHBOARD_VIEW2, // Dialogs types IDC_DIALOG_OPEN_SCENARIO, Loading @@ -175,11 +178,6 @@ export { uiSetAutomaticRefresh, uiChangeRefreshInterval, uiExecChangeShowApps, // Dashboard UI_EXEC_CHANGE_SHOW_DASHBOARD_CONFIG, UI_EXEC_CHANGE_DASHBOARD_VIEW1, UI_EXEC_CHANGE_DASHBOARD_VIEW2, uiExecChangeShowDashboardConfig, uiExecExpandDashboardConfig, uiExecChangeDashboardView1, Loading Loading
js-apps/meep-frontend/src/js/containers/dashboard-container.js→js-apps/meep-frontend/src/js/containers/exec/dashboard-container.js +69 −34 Original line number Diff line number Diff line Loading @@ -10,35 +10,35 @@ import { Slider } from '@rmwc/slider'; import moment from 'moment'; import * as d3 from 'd3'; import { blue } from './graph-utils'; import { blue } from '../graph-utils'; import IDCLineChart from './idc-line-chart'; import IDCGraph from './idc-graph'; import IDCAppsView from './idc-apps-view'; import IDSelect from '../components/helper-components/id-select'; import IDCVis from './idc-vis'; import ResizeableContainer from './resizeable-container'; import IDCGraph from '../idc-graph'; import IDCAppsView from '../idc-apps-view'; import IDSelect from '../../components/helper-components/id-select'; import IDCVis from '../idc-vis'; import ResizeableContainer from '../resizeable-container'; import { getScenarioNodeChildren, isApp } from '../util/scenario-utils'; } from '../../util/scenario-utils'; import { isDataPointOfType } from '../util/metrics'; } from '../../util/metrics'; import { execFakeChangeSelectedDestination, execChangeSourceNodeSelected, execChangeMetricsTimeIntervalDuration, execClearMetricsEpochs } from '../state/exec'; } from '../../state/exec'; import { uiExecChangeDashboardView1, uiExecChangeDashboardView2, uiExecExpandDashboardConfig } from '../state/ui'; } from '../../state/ui'; import { Loading @@ -53,10 +53,34 @@ import { LATENCY_VIEW, THROUGHPUT_VIEW, VIS_VIEW } from '../meep-constants'; } from '../../meep-constants'; const TIME_FORMAT = moment.HTML5_FMT.DATETIME_LOCAL_MS; const MIN_TIME_RANGE_VALUE = 15; const MAX_TIME_RANGE_VALUE = 60; const greyColor = 'grey'; const styles = { button: { marginRight: 0 }, slider: { container: { marginTop:10, marginBottom: 10, color: greyColor }, boundaryValues: { marginTop: 15 }, title: { marginBottom: 0 } } }; function colorArray(dataLength) { const colorScale = d3.interpolateInferno; // Other possible color scales: Loading Loading @@ -116,22 +140,36 @@ const TimeIntervalConfig = (props) => { </Button> ); } return ( <div style={{marginTop: 10}}> <Grid> <GridCell span={3}> <div style={{margin:10}}> <div> <div style={styles.slider.container}> <div style={styles.slider.title}> <span className="mdc-typography--headline8">Timeframe in secs </span> </div> <Grid> <GridCell span={1} style={styles.slider.boundaryValues}> <span>{MIN_TIME_RANGE_VALUE}</span> </GridCell> <GridCell span={10}> <Slider value={props.value} onChange={e => props.timeIntervalDurationChanged(e.detail.value)} onChange={e => props.changeTimeIntervalDuration(e.detail.value)} discrete min={5} max={60} min={MIN_TIME_RANGE_VALUE} max={MAX_TIME_RANGE_VALUE} step={1} /> </GridCell> <GridCell span={1} style={styles.slider.boundaryValues}> <span>{MAX_TIME_RANGE_VALUE}</span> </GridCell> </Grid> </div> </GridCell> Loading Loading @@ -199,7 +237,7 @@ const ConfigurationView = (props) => { </GridCell> </Grid> <TimeIntervalConfig timeIntervalDurationChanged={(value) => {props.timeIntervalDurationChanged(value);}} changeTimeIntervalDuration={(value) => {props.changeTimeIntervalDuration(value);}} stopSlidingWindow={props.stopSlidingWindow} startSlidingWindow={props.startSlidingWindow} slidingWindowStopped={props.slidingWindowStopped} Loading @@ -208,10 +246,6 @@ const ConfigurationView = (props) => { ); }; const buttonStyles = { marginRight: 0 }; const ViewForName = ( { keyForSvg, Loading Loading @@ -365,7 +399,7 @@ const DashboardConfiguration = (props) => { changeSourceNodeSelected={props.changeSourceNodeSelected} changeDisplayEdgeLabels={props.changeDisplayEdgeLabels} displayEdgeLabels={props.displayEdgeLabels} timeIntervalDurationChanged={props.timeIntervalDurationChanged} changeTimeIntervalDuration={props.changeTimeIntervalDuration} stopSlidingWindow={props.stopSlidingWindow} startSlidingWindow={props.startSlidingWindow} slidingWindowStopped={props.slidingWindowStopped} Loading @@ -375,7 +409,7 @@ const DashboardConfiguration = (props) => { const buttonConfig = !props.dashboardConfigExpanded ? ( <Button outlined style={buttonStyles} onClick={() => props.expandDashboardConfig(true)}> <Button outlined style={styles.button} onClick={() => props.expandDashboardConfig(true)}> Open </Button> ) Loading @@ -383,7 +417,7 @@ const DashboardConfiguration = (props) => { const buttonClose = props.dashboardConfigExpanded ? ( <Button outlined style={buttonStyles} onClick={() => props.expandDashboardConfig(false)}> <Button outlined style={styles.button} onClick={() => props.expandDashboardConfig(false)}> Close </Button> ) Loading @@ -391,6 +425,7 @@ const DashboardConfiguration = (props) => { return ( <Elevation z={2} className="component-style" style={{padding: 10, marginBottom: 10}} > Loading Loading @@ -671,7 +706,7 @@ class DashboardContainer extends Component { nodeIds={appIds} sourceNodeSelected={this.props.sourceNodeSelected} changeSourceNodeSelected={(nodeId) => this.props.changeSourceNodeSelected(appMap[nodeId])} timeIntervalDurationChanged={(duration) => {this.changeMetricsTimeIntervalDuration(duration);}} changeTimeIntervalDuration={(duration) => {this.changeMetricsTimeIntervalDuration(duration);}} stopSlidingWindow={() => this.stopSlidingWindow()} startSlidingWindow={() => this.startSlidingWindow()} slidingWindowStopped={this.state.slidingWindowStopped} Loading @@ -685,8 +720,8 @@ class DashboardContainer extends Component { <Grid> {!view1Present ? null : ( <GridCell span={span1} style={{paddingRight: 10}} className='chartContainer'> <Elevation z={2} <GridCell span={span1} className='chartContainer'> <Elevation z={2} className="component-style" style={{padding: 10}} > {view1} Loading @@ -696,7 +731,7 @@ class DashboardContainer extends Component { {!view2Present ? null : ( <GridCell span={span2} style={{marginLeft: -10, paddingLeft: 10}} className='chartContainer'> <Elevation z={2} <Elevation z={2} className="component-style" style={{padding: 10}} > {view2} Loading
js-apps/meep-frontend/src/js/containers/exec/exec-page-container.js +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import { connect } from 'react-redux'; import React, { Component } from 'react'; import { Grid, GridCell, GridInner } from '@rmwc/grid'; import { Elevation } from '@rmwc/elevation'; import DashboardContainer from '../dashboard-container'; import DashboardContainer from './dashboard-container'; import ExecPageScenarioButtons from './exec-page-scenario-buttons'; import HeadlineBar from '../../components/headline-bar'; Loading
js-apps/meep-frontend/src/js/containers/idc-line-chart.js→js-apps/meep-frontend/src/js/containers/exec/idc-line-chart.js +5 −4 Original line number Diff line number Diff line Loading @@ -19,8 +19,8 @@ import * as d3 from 'd3'; import React from 'react'; import uuid from 'uuid'; import {Axis, axisPropsFromTickScale, LEFT, BOTTOM} from 'react-d3-axis'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../meep-constants'; import { blue } from './graph-utils'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../../meep-constants'; import { blue } from '../graph-utils'; // const Axis = props => { // const axisRef = axis => { // axis && props.axisCreator(select(axis)); Loading @@ -32,10 +32,11 @@ import { blue } from './graph-utils'; const notNull = x => x; const IDCLineChart = (props) => { const keyForSvg=props.keyForSvg; let width = props.width; let yClipping = 45; const margin = {top: 20, right: 40, bottom: 30, left: 60}; let width = props.width - (margin.right + margin.left); let yClipping = 45; // const width = props.width; // - margin.left - margin.right; const height = props.height; // - margin.top - margin.bottom; Loading
js-apps/meep-frontend/src/js/containers/idc-line-chart-back.jsdeleted 100644 → 0 +0 −234 Original line number Diff line number Diff line /* * Copyright (c) 2019 * InterDigital Communications, Inc. * All rights reserved. * * The information provided herein is the proprietary and confidential * information of InterDigital Communications, Inc. */ import _ from 'lodash'; import React, { useRef, useEffect } from 'react'; import * as d3 from 'd3'; import { ME_LATENCY_METRICS, ME_THROUGHPUT_METRICS } from '../meep-constants'; const notNull = x => x; const IDCLineChartBack = props => { const d3Container = useRef(null); /* The useEffect Hook is for running side effects outside of React, for instance inserting elements into the DOM using D3 */ useEffect( () => { const margin = {top: 20, right: 40, bottom: 30, left: 60}; const width = props.width - margin.left - margin.right; const height = props.height - margin.top - margin.bottom; let mainGroup = d3.select(d3Container.current); if (mainGroup.select('g').size() === 0) { mainGroup = mainGroup.append('g') .attr('width', props.width + margin.left + margin.right) .attr('height', props.height + margin.top + margin.bottom) .attr('transform', `translate(${margin.left}, ${margin.top})`); } const flattenSeries = series => { return _.flatMap(Object.values(series)); }; const chart = (series) => { const destinations = props.selectedSource ? props.destinations.slice(-props.destinations.length) : []; const colorRange = destinations.map(s => props.colorForApp[s]); const yRange = [0, 200]; const timeRange = d3.extent(flattenSeries(series), d => new Date(d.timestamp)); const x = d3.scaleTime().domain(timeRange).range([0, width]); const y = d3.scaleLinear().domain(yRange).range([height - 50, 0]); const z = d3.scaleOrdinal().range(colorRange); // Axes const xAxis = d3.axisBottom(x); //.ticks(d3.timeSeconds); const yAxis = d3.axisLeft(y).scale(y) .tickSize(0.01); // const yAxisr = d3.axisLeft(y); // const dataLinePointFromDataPoint = key => point => { // if (point[key] === undefined) { // console.log('point[key] is undefined, for key ' + key + ' and point ', point); // return null; // } // return { // date: point.date, // value: point[key] // }; // }; const dataLineFromSeries = series => key => { const line = series[key].filter(notNull).filter(p => p.value); // .sort((a, b) => { // return x(new Date(a.timestamp)) - x(new Date(b.timestamp)); // }); //TODO: add point at props.startTime and props.endTime line.key = key; return line; }; let dataLines = destinations.map(dataLineFromSeries(props.series)); // TODO: remove dataLines = dataLines.length ? [dataLines[0]] : []; const valueLine = d3.line() .x(function(d) { return margin.left + x(new Date(d.timestamp)); }) .y(function(d) { return y(d.value) + margin.top; }) .curve(d3.curveMonotoneX); mainGroup.selectAll('.line') .data(dataLines) .join('path').attr('class', 'line') .attr('d', valueLine) .style('stroke', (d, i) => z(i)) .style('fill', 'none') .style('stroke-width', 3); // if (mainGroup.selectAll('.line').size() > 0) { // const linesMarginLeft = mainGroup.selectAll('.line').attr('margin-left'); // console.log('linesMarginLeft: ', linesMarginLeft); // } // Mobility events // const mobilityEventLine = d => `M${x(new Date(d.timestamp)) + margin.left},${y(yRange[0]) + margin.top} L${x(new Date(d.timestamp)) + margin.left},${y(yRange[1]) + margin.top}`; const mobilityEventLine = d => `M${x(new Date(d.timestamp)) + margin.left},${y(yRange[1]) + margin.top} L${x(new Date(d.timestamp)) + margin.left},${y(yRange[0]) + margin.top}`; mainGroup.selectAll('.mobilityEventLine') .data(props.mobilityEvents) .join('path') .attr('class', 'mobilityEventLine') .attr('d', mobilityEventLine) .attr('id', d => d.timestamp) .style('stroke', 'gray') .style('stroke-width', 1) .style('fill', 'none'); mainGroup.selectAll('.mobilityEventLineText') .data(props.mobilityEvents) .join('text') .attr('class', 'mobilityEventLineText') .style('stroke','gray') .style('stroke-width', 1) .style('fill','gray'); // .attr('x', d => x(new Date(d.timestamp)) + margin.left) // .attr('dy',50 + margin.top) mainGroup.selectAll('.mobilityEventLineTextPath').remove(); mainGroup.selectAll('.mobilityEventLineText') .data(props.mobilityEvents) .append('textPath') .attr('class', 'mobilityEventLineTextPath') .attr('xlink:href', d => `#${d.timestamp}`) .attr('stroke','gray') .attr('fill','gray') .text(d => `Mobility Event: ${d.src} to ${d.dest}`) .attr('transform', 'rotate(-180)'); const xAxisGroup = mainGroup.selectAll('.xaxis'); if (xAxisGroup.size() === 0) { mainGroup.append('g') .attr('class', 'xaxis') .attr('transform', 'translate(0,' + height + ')').call(xAxis); } else { xAxisGroup.attr('transform', 'translate(0,' + height + ')').call(xAxis); } mainGroup.selectAll('.xaxis').call(xAxis); const yAxisGroup = mainGroup.selectAll('.yaxis'); if (yAxisGroup.size() === 0) { mainGroup.append('g') .attr('class', 'yaxis') .attr('transform', 'translate(' + width + ', 0)') .style('z-index', '18') .call(yAxis); } else { yAxisGroup.attr('transform', 'translate(' + width + ', 0)'); } // text label for the y axis const labelForType = type => { switch (type) { case ME_LATENCY_METRICS: return 'Latency (ms)'; case ME_THROUGHPUT_METRICS: return 'Throughput (kbs)'; default: return ''; } }; const yAxisLabel = labelForType(props.dataType); if (!mainGroup.selectAll('.yLabel').size()) { mainGroup.append('text') .attr('class', 'yLabel') .attr('transform', 'rotate(-90)') .attr('y', 0 - margin.left + 10) .attr('x', 0 - (height / 2)) .attr('dy', '1em') .style('text-anchor', 'middle') .text(yAxisLabel); } else { mainGroup.selectAll('.yLabel') .text(yAxisLabel); } const yAxisGroup0 = mainGroup.selectAll('.yaxis0'); if (yAxisGroup0.size() === 0) { mainGroup.append('g') .attr('class', 'yaxis0') .attr('transform', 'translate(0, 0)') .style('z-index', '18') .call(yAxis); } else { yAxisGroup0.attr('transform', 'translate(0, 0)').style('z-index', '18'); } }; chart(props.series); }, /* useEffect has a dependency array (below). It's a list of dependency variables for this useEffect block. The block will run after mount and whenever any of these variables change. We still have to check if the variables are valid, but we do not have to compare old props to next props to decide whether to rerender. */ [props.data, d3Container.current]); return ( <div className='chart'> <svg //viewBox='0 -20 200 33' ref={d3Container} className='d3-component' height={props.height} width={props.width} > </svg> </div> ); }; export default IDCLineChartBack; No newline at end of file
js-apps/meep-frontend/src/js/state/ui/index.js +3 −5 Original line number Diff line number Diff line Loading @@ -154,6 +154,9 @@ export { // Action types EXEC_CHANGE_CURRENT_EVENT, UI_EXEC_CHANGE_SHOW_DASHBOARD_CONFIG, UI_EXEC_CHANGE_DASHBOARD_VIEW1, UI_EXEC_CHANGE_DASHBOARD_VIEW2, // Dialogs types IDC_DIALOG_OPEN_SCENARIO, Loading @@ -175,11 +178,6 @@ export { uiSetAutomaticRefresh, uiChangeRefreshInterval, uiExecChangeShowApps, // Dashboard UI_EXEC_CHANGE_SHOW_DASHBOARD_CONFIG, UI_EXEC_CHANGE_DASHBOARD_VIEW1, UI_EXEC_CHANGE_DASHBOARD_VIEW2, uiExecChangeShowDashboardConfig, uiExecExpandDashboardConfig, uiExecChangeDashboardView1, Loading