Unverified Commit f80d553d authored by Kevin Di Lallo's avatar Kevin Di Lallo Committed by GitHub
Browse files

Merge pull request #36 from renaudmx/fr_sp_29

Final touch ups
parents b51e524f 8884b6a9
Loading
Loading
Loading
Loading
+69 −34
Original line number Diff line number Diff line
@@ -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 {
@@ -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:
@@ -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>
@@ -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}
@@ -208,10 +246,6 @@ const ConfigurationView = (props) => {
  );
};

const buttonStyles = {
  marginRight: 0
};

const ViewForName = (
  {
    keyForSvg,
@@ -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}
@@ -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>
    )
@@ -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>
    )
@@ -391,6 +425,7 @@ const DashboardConfiguration = (props) => {

  return (
    <Elevation z={2}
      className="component-style"
      style={{padding: 10, marginBottom: 10}}
    >
    
@@ -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}
@@ -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}
@@ -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}
+1 −1
Original line number Diff line number Diff line
@@ -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';
+5 −4
Original line number Diff line number Diff line
@@ -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));
@@ -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;

+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
+3 −5
Original line number Diff line number Diff line
@@ -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,
@@ -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,