Merge branch 'latest' into 10.1.0
# Conflicts: # package.json
BIN
images/alberto.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
images/fire.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
images/flags/ar.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
images/flags/br.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
images/flags/co.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
images/flags/de.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
images/flags/es.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
images/flags/fr.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
images/flags/gb.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
images/flags/gr.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
images/flags/ie.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
images/flags/is.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
images/flags/it.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
images/flags/mt.png
Normal file
|
After Width: | Height: | Size: 136 B |
BIN
images/flags/no.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
images/flags/pe.png
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
images/flags/pt.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
images/flags/se.png
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
images/flags/uy.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
images/flags/ve.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
images/frost.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
images/horse.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
images/niall.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
images/phone.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
images/sean.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
images/smiley-sad.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/smiley.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/statue.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
images/sun.png
Normal file
|
After Width: | Height: | Size: 570 B |
53
package.json
@@ -29,31 +29,34 @@
|
||||
},
|
||||
"homepage": "http://www.ag-grid.com/",
|
||||
"devDependencies": {
|
||||
"babel-core": "6.24.x",
|
||||
"babel-loader": "6.4.x",
|
||||
"babel-preset-es2015": "6.24.x",
|
||||
"babel-preset-react": "6.24.x",
|
||||
"babel-preset-stage-0": "6.24.x",
|
||||
"babel-preset-stage-1": "6.24.x",
|
||||
"css-loader": "0.23.x",
|
||||
"style-loader": "0.13.x",
|
||||
"webpack": "1.12.x",
|
||||
"webpack-dev-server": "1.14.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"ag-grid": "10.0.x",
|
||||
"ag-grid-enterprise": "10.0.x",
|
||||
"ag-grid-react": "10.0.x",
|
||||
"bootstrap": "^3.3.7",
|
||||
"d3": "4.9.1",
|
||||
"file-loader": "^0.11.1",
|
||||
"lodash": "4.17.4",
|
||||
"react": "15.5.x",
|
||||
"react-dom": "15.5.x",
|
||||
"react-redux": "5.0.x",
|
||||
"redux": "3.6.x",
|
||||
"rimraf": "2.5.x"
|
||||
}
|
||||
"babel-core": "6.24.x",
|
||||
"babel-loader": "6.4.x",
|
||||
"babel-preset-es2015": "6.24.x",
|
||||
"babel-preset-react": "6.24.x",
|
||||
"babel-preset-stage-0": "6.24.x",
|
||||
"babel-preset-stage-1": "6.24.x",
|
||||
"css-loader": "0.23.x",
|
||||
"mkdirp": "0.5.1",
|
||||
"ncp": "2.0.0",
|
||||
"rimraf": "2.5.x",
|
||||
"style-loader": "0.13.x",
|
||||
"webpack": "1.12.x",
|
||||
"webpack-dev-server": "1.14.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "3.3.7",
|
||||
"d3": "4.9.1",
|
||||
"file-loader": "0.11.1",
|
||||
"lodash": "4.17.4",
|
||||
"react": "15.5.x",
|
||||
"react-dom": "15.5.x",
|
||||
"react-redux": "5.0.x",
|
||||
"redux": "3.6.x",
|
||||
"url-search-params-polyfill": "1.2.0",
|
||||
"ag-grid": "10.1.x",
|
||||
"ag-grid-enterprise": "10.1.x",
|
||||
"ag-grid-react": "10.1.x"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import MyApp from './myApp.jsx';
|
||||
// is there a better way of doing this?
|
||||
import 'ag-grid-root/dist/styles/ag-grid.css';
|
||||
import 'ag-grid-root/dist/styles/theme-fresh.css';
|
||||
|
||||
// waiting for dom to load before booting react. we could alternatively
|
||||
// put the index.js reference at the end fo the index.html, but i prefer this way.
|
||||
document.addEventListener('DOMContentLoaded', ()=> {
|
||||
var container = document.getElementById('myAppContainer');
|
||||
ReactDOM.render(
|
||||
React.createElement(MyApp),
|
||||
container
|
||||
);
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
.ag-cell {
|
||||
padding-top: 2px !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
.div-percent-bar {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.div-percent-value {
|
||||
position: absolute;
|
||||
padding-left: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.div-outer-div {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,356 +0,0 @@
|
||||
import React from "react";
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import "./myApp.css";
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
|
||||
export class DetailPanelCellRenderer extends React.Component{
|
||||
|
||||
|
||||
|
||||
render (){
|
||||
return <div><div class="full-width-panel">
|
||||
<div class="full-width-details">
|
||||
<div class="full-width-detail"><b>Name: </b>+parentRecord.name+</div>
|
||||
<div class="full-width-detail"><b>Account: </b>+parentRecord.account+</div>
|
||||
</div>
|
||||
<div class="full-width-grid"></div>
|
||||
<div class="full-width-grid-toolbar">
|
||||
<img class="full-width-phone-icon" src="https://www.ag-grid.com/images/phone.png"/>
|
||||
<button><img src="https://www.ag-grid.com/images/fire.png"/></button>
|
||||
<button><img src="https://www.ag-grid.com/images/frost.png"/></button>
|
||||
<button><img src="https://www.ag-grid.com/images/sun.png"/></button>
|
||||
<input class="full-width-search" placeholder="Search..."/>
|
||||
</div>
|
||||
</div></div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
// a list of names we pick from when generating data
|
||||
var firstnames = ['Sophia','Emma','Olivia','Isabella','Mia','Ava','Lily','Zoe','Emily','Chloe','Layla','Madison','Madelyn','Abigail','Aubrey','Charlotte','Amelia','Ella','Kaylee','Avery','Aaliyah','Hailey','Hannah','Addison','Riley','Harper','Aria','Arianna','Mackenzie','Lila','Evelyn','Adalyn','Grace','Brooklyn','Ellie','Anna','Kaitlyn','Isabelle','Sophie','Scarlett','Natalie','Leah','Sarah','Nora','Mila','Elizabeth','Lillian','Kylie','Audrey','Lucy','Maya'];
|
||||
var lastnames = ['Smith','Jones','Williams','Taylor','Brown','Davies','Evans','Wilson','Thomas','Johnson'];
|
||||
|
||||
var images = ['niall','sean','alberto','statue','horse'];
|
||||
// each call gets a unique id, nothing to do with the grid, just help make the sample
|
||||
// data more realistic
|
||||
var callIdSequence = 555;
|
||||
|
||||
// method creates all the data, both the top level grid and the lower level grids
|
||||
function createRowData() {
|
||||
var rowData = [];
|
||||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
var firstName = firstnames[Math.floor(Math.random()*firstnames.length)];
|
||||
var lastName = lastnames[Math.floor(Math.random()*lastnames.length)];
|
||||
|
||||
var image = images[i % images.length];
|
||||
|
||||
var totalDuration = 0;
|
||||
|
||||
var callRecords = [];
|
||||
// call count is random number between 20 and 120
|
||||
var callCount = Math.floor(Math.random() * 100) + 20;
|
||||
for (var j = 0; j<callCount; j++) {
|
||||
// duration is random number between 20 and 120
|
||||
var callDuration = Math.floor(Math.random() * 100) + 20;
|
||||
var callRecord = {
|
||||
callId: callIdSequence++,
|
||||
duration: callDuration,
|
||||
switchCode: 'SW' + Math.floor(Math.random() * 10),
|
||||
// 50% chance of in vs out
|
||||
direction: (Math.random()>.5) ? 'In' : 'Out',
|
||||
// made up number
|
||||
number: '(0' + Math.floor(Math.random() * 10) + ') ' + Math.floor(Math.random() * 100000000)
|
||||
};
|
||||
callRecords.push(callRecord);
|
||||
totalDuration += callDuration;
|
||||
}
|
||||
|
||||
var record = {
|
||||
name: firstName + ' ' + lastName,
|
||||
account: i + 177000,
|
||||
totalCalls: callCount,
|
||||
image: image,
|
||||
// convert from seconds to minutes
|
||||
totalMinutes: totalDuration / 60,
|
||||
callRecords: callRecords
|
||||
};
|
||||
rowData.push(record);
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
var minuteCellFormatter = function (params) {
|
||||
return params.value.toLocaleString() + 'm';
|
||||
};
|
||||
|
||||
var secondCellFormatter= function (params) {
|
||||
return params.value.toLocaleString() + 's';
|
||||
};
|
||||
|
||||
var masterColumnDefs = [
|
||||
{headerName: 'Name', field: 'name',
|
||||
// left column is going to act as group column, with the expand / contract controls
|
||||
cellRenderer: 'group',
|
||||
// we don't want the child count - it would be one each time anyway as each parent
|
||||
// not has exactly one child node
|
||||
cellRendererParams: { suppressCount: true }
|
||||
},
|
||||
{headerName: 'Account', field: 'account'},
|
||||
{headerName: 'Calls', field: 'totalCalls'},
|
||||
{headerName: 'Minutes', field: 'totalMinutes', cellFormatter: minuteCellFormatter}
|
||||
];
|
||||
|
||||
var detailColumnDefs = [
|
||||
{headerName: 'Call ID', field: 'callId', cellClass: 'call-record-cell'},
|
||||
{headerName: 'Direction', field: 'direction', cellClass: 'call-record-cell'},
|
||||
{headerName: 'Number', field: 'number', cellClass: 'call-record-cell'},
|
||||
{headerName: 'Duration', field: 'duration', cellClass: 'call-record-cell', cellFormatter: secondCellFormatter},
|
||||
{headerName: 'Switch', field: 'switchCode', cellClass: 'call-record-cell'}
|
||||
];
|
||||
|
||||
var rowData = createRowData();
|
||||
export default class MyApp extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
quickFilterText: null,
|
||||
showGrid: true,
|
||||
showToolPanel: false,
|
||||
icons: {
|
||||
columnRemoveFromGroup: '<i class="fa fa-remove"/>',
|
||||
filter: '<i class="fa fa-filter"/>',
|
||||
sortAscending: '<i class="fa fa-long-arrow-down"/>',
|
||||
sortDescending: '<i class="fa fa-long-arrow-up"/>',
|
||||
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
||||
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
||||
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
||||
columnGroupClosed: '<i class="fa fa-plus-square-o"/>'
|
||||
}
|
||||
};
|
||||
|
||||
// the grid options are optional, because you can provide every property
|
||||
// to the grid via standard React properties. however, the react interface
|
||||
// doesn't block you from using the standard JavaScript interface if you
|
||||
// wish. Maybe you have the gridOptions stored as JSON on your server? If
|
||||
// you do, the providing the gridOptions as a standalone object is just
|
||||
// what you want!
|
||||
this.gridOptions = {
|
||||
columnDefs: masterColumnDefs,
|
||||
rowData: rowData,
|
||||
//We register the react date component that ag-grid will use to render
|
||||
// this is how you listen for events using gridOptions
|
||||
onModelUpdated: function () {
|
||||
console.log('event onModelUpdated received');
|
||||
},
|
||||
defaultColDef : {
|
||||
headerComponentParams : {
|
||||
menuIcon: 'fa-bars'
|
||||
}
|
||||
},
|
||||
// this is a simple property
|
||||
rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios
|
||||
};
|
||||
}
|
||||
|
||||
onShowGrid(show) {
|
||||
this.setState({
|
||||
showGrid: show
|
||||
});
|
||||
}
|
||||
|
||||
onToggleToolPanel(event) {
|
||||
this.setState({showToolPanel: event.target.checked});
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.api = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
params.api.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
selectAll() {
|
||||
this.api.selectAll();
|
||||
}
|
||||
|
||||
deselectAll() {
|
||||
this.api.deselectAll();
|
||||
}
|
||||
|
||||
setCountryVisible(visible) {
|
||||
this.columnApi.setColumnVisible('country', visible);
|
||||
}
|
||||
|
||||
onQuickFilterText(event) {
|
||||
this.setState({quickFilterText: event.target.value});
|
||||
}
|
||||
|
||||
onCellClicked(event) {
|
||||
console.log('onCellClicked: ' + event.data.name + ', col ' + event.colIndex);
|
||||
}
|
||||
|
||||
onRowSelected(event) {
|
||||
console.log('onRowSelected: ' + event.node.data.name);
|
||||
}
|
||||
|
||||
onRefreshData() {
|
||||
var newRowData = new RowDataFactory().createRowData();
|
||||
this.setState({
|
||||
rowData: newRowData
|
||||
});
|
||||
}
|
||||
|
||||
invokeSkillsFilterMethod() {
|
||||
var skillsFilter = this.api.getFilterInstance('skills');
|
||||
var componentInstance = skillsFilter.getFrameworkComponentInstance();
|
||||
componentInstance.helloFromSkillsFilter();
|
||||
}
|
||||
|
||||
dobFilter () {
|
||||
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
||||
dateFilterComponent.setFilterType('equals');
|
||||
dateFilterComponent.setDateFrom('2000-01-01');
|
||||
this.gridOptions.api.onFilterChanged();
|
||||
|
||||
}
|
||||
|
||||
onIsFullWidthCell (rowNode) {
|
||||
return rowNode.level === 1;
|
||||
}
|
||||
|
||||
onGetRowHeight (params) {
|
||||
var rowIsDetailRow = params.node.level===1;
|
||||
// return 100 when detail row, otherwise return 25
|
||||
return rowIsDetailRow ? 75 : 25;
|
||||
}
|
||||
|
||||
onGetNodeChildDetails (record) {
|
||||
if (record.callRecords) {
|
||||
return {
|
||||
group: true,
|
||||
// the key is used by the default group cellRenderer
|
||||
key: record.name,
|
||||
// provide ag-Grid with the children of this group
|
||||
children: [record.callRecords],
|
||||
// for demo, expand the third row by default
|
||||
expanded: record.account === 177005
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
var gridTemplate;
|
||||
var bottomHeaderTemplate;
|
||||
var topHeaderTemplate;
|
||||
|
||||
topHeaderTemplate = (
|
||||
<div>
|
||||
<div style={{float: 'right'}}>
|
||||
<input type="text" onChange={this.onQuickFilterText.bind(this)}
|
||||
placeholder="Type text to filter..."/>
|
||||
<button id="btDestroyGrid" disabled={!this.state.showGrid}
|
||||
onClick={this.onShowGrid.bind(this, false)}>Destroy Grid
|
||||
</button>
|
||||
<button id="btCreateGrid" disabled={this.state.showGrid} onClick={this.onShowGrid.bind(this, true)}>
|
||||
Create Grid
|
||||
</button>
|
||||
</div>
|
||||
<div style={{padding: '4px'}}>
|
||||
<b>Employees Skills and Contact Details</b> <span id="rowCount"/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// showing the bottom header and grid is optional, so we put in a switch
|
||||
if (this.state.showGrid) {
|
||||
bottomHeaderTemplate = (
|
||||
<div>
|
||||
<div style={{padding: 4}} className={'toolbar'}>
|
||||
<span>
|
||||
Grid API:
|
||||
<button onClick={this.selectAll.bind(this)}>Select All</button>
|
||||
<button onClick={this.deselectAll.bind(this)}>Clear Selection</button>
|
||||
</span>
|
||||
<span style={{marginLeft: 20}}>
|
||||
Column API:
|
||||
<button onClick={this.setCountryVisible.bind(this, false)}>Hide Country Column</button>
|
||||
<button onClick={this.setCountryVisible.bind(this, true)}>Show Country Column</button>
|
||||
</span>
|
||||
</div>
|
||||
<div style={{clear: 'both'}}></div>
|
||||
<div style={{padding: 4}} className={'toolbar'}>
|
||||
<span>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this.onToggleToolPanel.bind(this)}/>
|
||||
Show Tool Panel
|
||||
</label>
|
||||
<button onClick={this.onRefreshData.bind(this)}>Refresh Data</button>
|
||||
</span>
|
||||
<span style={{marginLeft: 20}}>
|
||||
Filter API:
|
||||
<button onClick={this.invokeSkillsFilterMethod.bind(this, false)}>Invoke Skills Filter Method</button>
|
||||
<button onClick={this.dobFilter.bind(this)}>DOB equals to 01/01/2000</button>
|
||||
</span>
|
||||
</div>
|
||||
<div style={{clear: 'both'}}></div>
|
||||
</div>
|
||||
);
|
||||
gridTemplate = (
|
||||
<div style={{height: 400}} className="ag-fresh">
|
||||
<AgGridReact
|
||||
// gridOptions is optional - it's possible to provide
|
||||
// all values as React props
|
||||
gridOptions={this.gridOptions}
|
||||
|
||||
// listening for events
|
||||
onGridReady={this.onGridReady.bind(this)}
|
||||
onRowSelected={this.onRowSelected.bind(this)}
|
||||
onCellClicked={this.onCellClicked.bind(this)}
|
||||
|
||||
// binding to simple properties
|
||||
showToolPanel={this.state.showToolPanel}
|
||||
quickFilterText={this.state.quickFilterText}
|
||||
|
||||
// binding to an object property
|
||||
icons={this.state.icons}
|
||||
|
||||
|
||||
// no binding, just providing hard coded strings for the properties
|
||||
suppressRowClickSelection="true"
|
||||
rowSelection="multiple"
|
||||
enableColResize="true"
|
||||
enableSorting="true"
|
||||
enableFilter="true"
|
||||
groupHeaders="true"
|
||||
rowHeight="22"
|
||||
// we cannot filter on the groups, as filters work on the child nodes, and in this example
|
||||
// the child nodes are not aggregations of the parent.
|
||||
suppressMenuFilterPanel="true"
|
||||
isFullWidthCell = {this.onIsFullWidthCell.bind(this)}
|
||||
// see ag-Grid docs cellRenderer for details on how to build cellRenderers
|
||||
fullWidthCellRendererFramework= {DetailPanelCellRenderer}
|
||||
getRowHeight={this.onGetRowHeight.bind(this)}
|
||||
getNodeChildDetails={this.onGetNodeChildDetails.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <div style={{width: '1024px'}}>
|
||||
<div style={{padding: '4px'}}>
|
||||
{topHeaderTemplate}
|
||||
{bottomHeaderTemplate}
|
||||
{gridTemplate}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
export default class ColDefFactory {
|
||||
createColDefs() {
|
||||
return [
|
||||
{headerName: "Athlete", field: "athlete", width: 200},
|
||||
{headerName: "Age", field: "age", width: 90},
|
||||
{headerName: "Gold", field: "gold", width: 100, aggFunc: 'sum'},
|
||||
{headerName: "Silver", field: "silver", width: 100, aggFunc: 'sum'},
|
||||
{headerName: "Bronze", field: "bronze", width: 100, aggFunc: 'sum'},
|
||||
{headerName: "Total", field: "total", width: 100, aggFunc: 'sum'},
|
||||
{headerName: "Country", field: "country", width: 120, rowGroupIndex: 0},
|
||||
{headerName: "Year", field: "year", width: 90},
|
||||
{headerName: "Date", field: "date", width: 110},
|
||||
{headerName: "Sport", field: "sport", width: 110}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import MyApp from './myApp.jsx';
|
||||
// is there a better way of doing this?
|
||||
import 'ag-grid-root/dist/styles/ag-grid.css';
|
||||
import 'ag-grid-root/dist/styles/theme-fresh.css';
|
||||
|
||||
// waiting for dom to load before booting react. we could alternatively
|
||||
// put the index.js reference at the end fo the index.html, but i prefer this way.
|
||||
document.addEventListener('DOMContentLoaded', ()=> {
|
||||
var container = document.getElementById('myAppContainer');
|
||||
ReactDOM.render(
|
||||
React.createElement(MyApp),
|
||||
container
|
||||
);
|
||||
});
|
||||
@@ -1,99 +0,0 @@
|
||||
import React from "react";
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import ColDefFactory from "./ColDefFactory.jsx";
|
||||
import "./myApp.css";
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
|
||||
export default class MyApp extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
showToolPanel: false,
|
||||
columnDefs: new ColDefFactory().createColDefs(),
|
||||
rowData: null,
|
||||
};
|
||||
|
||||
this.gridOptions = {
|
||||
groupRowInnerRenderer: function (params) {
|
||||
var FLAG_CODES = {
|
||||
'Ireland': 'ie',
|
||||
'United States': 'us',
|
||||
'Russia': 'ru',
|
||||
'Australia': 'au',
|
||||
'Canada': 'ca',
|
||||
'Norway': 'no',
|
||||
'China': 'cn',
|
||||
'Zimbabwe': 'zw',
|
||||
'Netherlands': 'nl',
|
||||
'South Korea': 'kr',
|
||||
'Croatia': 'hr',
|
||||
'France': 'fr'
|
||||
};
|
||||
|
||||
var flagCode = FLAG_CODES[params.node.key];
|
||||
|
||||
var html = '';
|
||||
if (flagCode) {
|
||||
html += '<img class="flag" border="0" width="20" height="15" src="https://flags.fmcdn.net/data/flags/mini/' + flagCode + '.png">'
|
||||
}
|
||||
|
||||
html += '<span class="groupTitle"> COUNTRY_NAME</span>'.replace('COUNTRY_NAME', params.node.key);
|
||||
html += '<span class="medal gold"> Gold: GOLD_COUNT</span>'.replace('GOLD_COUNT', params.data.gold);
|
||||
html += '<span class="medal silver"> Silver: SILVER_COUNT</span>'.replace('SILVER_COUNT', params.data.silver);
|
||||
html += '<span class="medal bronze"> Bronze: BRONZE_COUNT</span>'.replace('BRONZE_COUNT', params.data.bronze);
|
||||
|
||||
return html;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.api = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
var that = this;
|
||||
var httpRequest = new XMLHttpRequest();
|
||||
httpRequest.open('GET', '/olympicWinners.json');
|
||||
httpRequest.send();
|
||||
httpRequest.onreadystatechange = function() {
|
||||
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
|
||||
var httpResult = JSON.parse(httpRequest.responseText);
|
||||
that.api.setRowData(httpResult);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
var gridTemplate = (
|
||||
<div style={{height: 400}} className="ag-fresh">
|
||||
<AgGridReact
|
||||
// gridOptions is optional - it's possible to provide
|
||||
// all values as React props
|
||||
gridOptions={this.gridOptions}
|
||||
|
||||
// listening for events
|
||||
onGridReady={this.onGridReady.bind(this)}
|
||||
|
||||
// binding to array properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
groupUseEntireRow="true"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return <div style={{width: '800px'}}>
|
||||
<div>
|
||||
{gridTemplate}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import MyApp from './myApp.jsx';
|
||||
|
||||
import 'ag-grid-root/dist/styles/ag-grid.css';
|
||||
import 'ag-grid-root/dist/styles/theme-fresh.css';
|
||||
|
||||
// waiting for dom to load before booting react. we could alternatively
|
||||
// put the index.js reference at the end fo the index.html, but i prefer this way.
|
||||
document.addEventListener('DOMContentLoaded', ()=> {
|
||||
var container = document.getElementById('myAppContainer');
|
||||
ReactDOM.render(
|
||||
React.createElement(MyApp),
|
||||
container
|
||||
);
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
.ag-cell {
|
||||
padding-top: 2px !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
.div-percent-bar {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.div-percent-value {
|
||||
position: absolute;
|
||||
padding-left: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.div-outer-div {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
16
src-trader-dashboard/actions/fxDataActions.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
|
||||
export function fxDataUpdated(fxData) {
|
||||
return {
|
||||
type: 'FX_DATA_CHANGED',
|
||||
fxData: cloneDeep(fxData)
|
||||
};
|
||||
}
|
||||
|
||||
export function fxTopMoversUpdated(fxTopMovers) {
|
||||
return {
|
||||
type: 'FX_TOP_MOVERS_CHANGED',
|
||||
fxTopMovers: cloneDeep(fxTopMovers)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
|
||||
26
src-trader-dashboard/components/FxPanel.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import FxDataService from "../services/FxDataService.jsx";
|
||||
import FxQuoteMatrix from "./FxQuoteMatrix.jsx";
|
||||
import TopMoversGrid from "./TopMoversGrid.jsx";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.fxDataService = new FxDataService();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div style={{float: "left", marginRight: 25}}>
|
||||
<FxQuoteMatrix fxDataService={this.fxDataService}/>
|
||||
</div>
|
||||
<div style={{float: "left"}}>
|
||||
<TopMoversGrid fxDataService={this.fxDataService}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +1,17 @@
|
||||
import React, {Component} from "react";
|
||||
import {connect} from "react-redux";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
import ExchangeService from "../services/ExchangeService.jsx";
|
||||
import assign from "lodash/assign";
|
||||
import uniq from "lodash/uniq";
|
||||
|
||||
class FxQuoteMatrix extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.exchangeService = new ExchangeService();
|
||||
|
||||
this.state = {
|
||||
columnDefs: this.exchangeService.getFxMatrixHeaderNames(),
|
||||
// rowData: this.exchangeService.getFxMatrixSnapshot()
|
||||
columnDefs: this.props.fxDataService.getFxMatrixHeaderNames()
|
||||
};
|
||||
|
||||
// grid events
|
||||
@@ -22,58 +21,49 @@ class FxQuoteMatrix extends Component {
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
if (this.props.rowData) {
|
||||
this.gridApi.setRowData(this.props.rowData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// componentWillUnmount() {
|
||||
// this.exchangeService.removeSubscribers();
|
||||
// }
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
console.log(props);
|
||||
// if (nextProps.selectedExchange.supportedStocks !== this.props.selectedExchange.supportedStocks) {
|
||||
// if (!this.gridApi) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// const currentSymbols = this.props.selectedExchange.supportedStocks;
|
||||
// const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
||||
//
|
||||
// // Unsubscribe to current ones that will be removed
|
||||
// const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
||||
// forEach(symbolsRemoved, symbol => {
|
||||
// this.exchangeService.removeSubscriber(this.updateQuote, symbol);
|
||||
// });
|
||||
//
|
||||
// // Subscribe to new ones that need to be added
|
||||
// const symbolsAdded = difference(nextSymbols, currentSymbols);
|
||||
// forEach(symbolsAdded, symbol => {
|
||||
// this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
||||
// });
|
||||
//
|
||||
// // Remove ag-grid nodes as necessary
|
||||
// const nodesToRemove = [];
|
||||
// this.gridApi.forEachNode(node => {
|
||||
// const {data} = node;
|
||||
// if (includes(symbolsRemoved, data.symbol)) {
|
||||
// nodesToRemove.push(node);
|
||||
// }
|
||||
// });
|
||||
// this.gridApi.removeItems(nodesToRemove);
|
||||
//
|
||||
// // Insert new ag-grid nodes as necessary
|
||||
// this.gridApi.addItems(map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol)));
|
||||
// }
|
||||
const newRowData = nextProps.rowData;
|
||||
|
||||
const updatedNodes = [];
|
||||
const updatedCols = [];
|
||||
|
||||
for (let i = 0; i < newRowData.length; i++) {
|
||||
// note that for this use case we assume the existing and new row data have the same
|
||||
// row and column order
|
||||
let node = this.gridApi.getModel().getRow(i);
|
||||
let newRow = newRowData[i];
|
||||
|
||||
const {data} = node;
|
||||
let updated = false;
|
||||
for (const def of this.state.columnDefs) {
|
||||
if (data[def.field] !== newRow[def.field]) {
|
||||
updatedCols.push(def.field);
|
||||
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated) {
|
||||
assign(data, newRow);
|
||||
updatedNodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
this.gridApi.refreshCells(updatedNodes, uniq(updatedCols));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 500, width: "100%"}}
|
||||
<div style={{height: 410, width: 800}}
|
||||
className="ag-fresh">
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
enableSorting="false"
|
||||
enableFilter="false"
|
||||
|
||||
@@ -88,7 +78,7 @@ class FxQuoteMatrix extends Component {
|
||||
export default connect(
|
||||
(state) => {
|
||||
return {
|
||||
rowData: state.fxRowData
|
||||
rowData: state.fxData
|
||||
}
|
||||
}
|
||||
)(FxQuoteMatrix);
|
||||
@@ -1,8 +1,5 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
import map from "lodash/map";
|
||||
@@ -44,15 +41,6 @@ export default class extends Component {
|
||||
cellFormatter: this.numberFormatter,
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellStyle: {'text-align': 'right'}
|
||||
},
|
||||
{
|
||||
headerName: 'Recommendation',
|
||||
field: 'recommendation',
|
||||
cellEditor: 'richSelect',
|
||||
cellEditorParams: {
|
||||
values: ['Buy', 'Hold', 'Sell']
|
||||
},
|
||||
editable: true
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -61,10 +49,10 @@ export default class extends Component {
|
||||
|
||||
// grid events
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.onRowClicked = this.onRowClicked.bind(this);
|
||||
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||
|
||||
// component events
|
||||
this.updateQuote = this.updateQuote.bind(this);
|
||||
this.updateSymbol = this.updateSymbol.bind(this);
|
||||
}
|
||||
|
||||
numberFormatter(params) {
|
||||
@@ -83,16 +71,20 @@ export default class extends Component {
|
||||
let rowData = map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol));
|
||||
this.gridApi.addItems(rowData);
|
||||
|
||||
// select the first symbol to show the chart
|
||||
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onRowClicked(params) {
|
||||
this.props.onRowClicked(params.data.symbol);
|
||||
onSelectionChanged() {
|
||||
let selectedNode = this.gridApi.getSelectedNodes()[0];
|
||||
this.props.onSelectionChanged(selectedNode ? selectedNode.data.symbol : null);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.props.selectedExchange.supportedStocks.forEach(symbol => {
|
||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
||||
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,6 +97,7 @@ export default class extends Component {
|
||||
if (!this.gridApi) {
|
||||
return;
|
||||
}
|
||||
this.gridApi.deselectAll();
|
||||
|
||||
const currentSymbols = this.props.selectedExchange.supportedStocks;
|
||||
const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
||||
@@ -112,13 +105,13 @@ export default class extends Component {
|
||||
// Unsubscribe to current ones that will be removed
|
||||
const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
||||
forEach(symbolsRemoved, symbol => {
|
||||
this.exchangeService.removeSubscriber(this.updateQuote, symbol);
|
||||
this.exchangeService.removeSubscriber(this.updateSymbol, symbol);
|
||||
});
|
||||
|
||||
// Subscribe to new ones that need to be added
|
||||
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
||||
forEach(symbolsAdded, symbol => {
|
||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
||||
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
||||
});
|
||||
|
||||
// Remove ag-grid nodes as necessary
|
||||
@@ -132,11 +125,15 @@ export default class extends Component {
|
||||
this.gridApi.removeItems(nodesToRemove);
|
||||
|
||||
// Insert new ag-grid nodes as necessary
|
||||
this.gridApi.addItems(map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol)));
|
||||
let rowData = map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol));
|
||||
this.gridApi.addItems(rowData);
|
||||
|
||||
// select the first symbol to show the chart
|
||||
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
updateQuote(quote) {
|
||||
updateSymbol(symbol) {
|
||||
if (!this.gridApi) {
|
||||
// the grid isn't ready yet
|
||||
return;
|
||||
@@ -147,13 +144,13 @@ export default class extends Component {
|
||||
|
||||
this.gridApi.forEachNode(node => {
|
||||
const {data} = node;
|
||||
if (data.symbol === quote.symbol) {
|
||||
if (data.symbol === symbol.symbol) {
|
||||
for (const def of this.state.columnDefs) {
|
||||
if (data[def.field] !== quote[def.field]) {
|
||||
if (data[def.field] !== symbol[def.field]) {
|
||||
updatedCols.push(def.field);
|
||||
}
|
||||
}
|
||||
assign(data, quote);
|
||||
assign(data, symbol);
|
||||
updatedNodes.push(node);
|
||||
}
|
||||
});
|
||||
@@ -163,16 +160,17 @@ export default class extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 500, width: 800}}
|
||||
<div style={{height: 410, width: 800}}
|
||||
className="ag-fresh">
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
enableSorting="true"
|
||||
rowSelection="single"
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}
|
||||
onRowClicked={this.onRowClicked}>
|
||||
onSelectionChanged={this.onSelectionChanged}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ export default class extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps, nextState) {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.selectedSymbol &&
|
||||
nextProps.selectedSymbol !== this.props.selectedSymbol) {
|
||||
let stockDetail = this.exchangeService.getTickerDetail(nextProps.selectedSymbol);
|
||||
@@ -35,7 +35,7 @@ export default class extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.selectedSymbol !== this.props.selectedSymbol;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class extends Component {
|
||||
|
||||
static get defaultProps() {
|
||||
return {
|
||||
graphHeight: 320,
|
||||
graphHeight: 230,
|
||||
graphWidth: 400
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, {Component} from "react";
|
||||
|
||||
import PriceChangesGrid from "./PriceChangesGrid.jsx";
|
||||
import StockDetailPanel from "./StockDetailPanel.jsx";
|
||||
import FxQuoteMatrix from "./FxQuoteMatrix.jsx";
|
||||
import FxPanel from "./FxPanel.jsx";
|
||||
|
||||
export default class extends Component {
|
||||
constructor(props) {
|
||||
@@ -12,7 +12,7 @@ export default class extends Component {
|
||||
selectedSymbol: null
|
||||
};
|
||||
|
||||
this.onRowClicked = this.onRowClicked.bind(this);
|
||||
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@@ -28,7 +28,7 @@ export default class extends Component {
|
||||
nextState.selectedSymbol !== this.state.selectedSymbol;
|
||||
}
|
||||
|
||||
onRowClicked(selectedSymbol) {
|
||||
onSelectionChanged(selectedSymbol) {
|
||||
this.setState({
|
||||
selectedSymbol
|
||||
})
|
||||
@@ -37,18 +37,18 @@ export default class extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div style={{width: 1250}}>
|
||||
{/*<div>*/}
|
||||
{/*<div style={{float: "left", marginRight: 25}}>*/}
|
||||
{/*<PriceChangesGrid selectedExchange={this.props.selectedExchange}*/}
|
||||
{/*onRowClicked={this.onRowClicked}/>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div style={{float: "left"}}>*/}
|
||||
{/*<StockDetailPanel selectedSymbol={this.state.selectedSymbol}*/}
|
||||
{/*exchangeName={this.props.selectedExchange.name}/>*/}
|
||||
{/*</div>*/}
|
||||
{/*</div>*/}
|
||||
<div>
|
||||
<div style={{float: "left", marginRight: 25}}>
|
||||
<PriceChangesGrid selectedExchange={this.props.selectedExchange}
|
||||
onSelectionChanged={this.onSelectionChanged}/>
|
||||
</div>
|
||||
<div style={{float: "left"}}>
|
||||
<StockDetailPanel selectedSymbol={this.state.selectedSymbol}
|
||||
exchangeName={this.props.selectedExchange.name}/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{width: "100%", clear: "both", paddingTop: 25}}>
|
||||
<FxQuoteMatrix/>
|
||||
<FxPanel/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class extends Component {
|
||||
this.updatePriceDelta(this.props.pricingDelta);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps, nextState) {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!isEqual(this.props.pricingDelta, nextProps.pricingDelta)) {
|
||||
this.updatePriceDelta(nextProps.pricingDelta);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export default class extends Component {
|
||||
|
||||
let swingStyle = this.state.delta >= 0 ? positiveSwingStyle : negativeSwingStyle;
|
||||
|
||||
if(!this.props.pricingDelta) {
|
||||
if (!this.props.pricingDelta) {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
|
||||
88
src-trader-dashboard/components/TopMoversGrid.jsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React, {Component} from "react";
|
||||
import {connect} from "react-redux";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
class TopMoversGrid extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
columnDefs: [
|
||||
{
|
||||
field: 'symbol',
|
||||
headerName: 'Symbol'
|
||||
},
|
||||
{
|
||||
field: 'last',
|
||||
headerName: 'Last',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right'
|
||||
},
|
||||
{
|
||||
field: 'net',
|
||||
headerName: 'Net',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right'
|
||||
},
|
||||
{
|
||||
field: 'pct_net_change',
|
||||
headerName: '% NC',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right',
|
||||
sort: 'desc',
|
||||
cellFormatter(params) {
|
||||
return params.value.toFixed(2)
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
// grid events
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||
}
|
||||
|
||||
getRowNodeId(data) {
|
||||
return data.symbol;
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 410, width: 400}}
|
||||
className="ag-fresh">
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.props.rowData}
|
||||
enableSorting
|
||||
enableFilter="false"
|
||||
animateRows
|
||||
deltaRowDataMode
|
||||
getRowNodeId={this.getRowNodeId}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state) => {
|
||||
return {
|
||||
rowData: state.fxTopMovers
|
||||
}
|
||||
}
|
||||
)(TopMoversGrid);
|
||||
@@ -0,0 +1,42 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class HorizontalBarComponent extends Component {
|
||||
|
||||
render() {
|
||||
let positiveChange = {
|
||||
fill: "green"
|
||||
};
|
||||
|
||||
let negativeChange = {
|
||||
fill: "red"
|
||||
};
|
||||
|
||||
let text = {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
width: "100%",
|
||||
textAlign: "right"
|
||||
};
|
||||
|
||||
let pctNetChange = this.props.value;
|
||||
let pctNetChangeBar = Math.min(Math.abs(pctNetChange) * 100, 100) / 2;
|
||||
|
||||
let barWidth = `${pctNetChangeBar}%`;
|
||||
let barStyle = pctNetChange >= 0 ? positiveChange : negativeChange;
|
||||
let barX = `${pctNetChange >= 0 ? '50' : 50 - pctNetChangeBar}%`;
|
||||
return (
|
||||
<div style={{position: 'relative'}}>
|
||||
<div style={{width: "50%"}}>
|
||||
<svg width="100%" preserveAspectRatio="none">
|
||||
<rect x={barX} y="0" width={barWidth} height="20px" rx="4" ry="4" style={barStyle}/>
|
||||
</svg>
|
||||
</div>
|
||||
<div style={text}>{pctNetChange}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalBarComponent.propTypes = {
|
||||
params: React.PropTypes.object
|
||||
};
|
||||
@@ -3,13 +3,17 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="dist/bundle.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="dist/react-trader.js" charset="utf-8"></script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ag-fresh .ag-value-change-value-highlight {
|
||||
background-color: #afbcff;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right
|
||||
}
|
||||
@@ -44,7 +48,7 @@
|
||||
background-image: linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%), linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%);
|
||||
}
|
||||
|
||||
.fx-postive {
|
||||
.fx-positive {
|
||||
border-top: 20px solid #3ACFD5;
|
||||
border-right: 20px solid #3a4ed5;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
@@ -4,16 +4,14 @@ import React from "react";
|
||||
import {render} from "react-dom";
|
||||
|
||||
import {Provider} from "react-redux";
|
||||
import {createStore} from "redux";
|
||||
|
||||
import TraderDashboard from "./components/TraderDashboard.jsx";
|
||||
|
||||
import "ag-grid-root/dist/styles/ag-grid.css";
|
||||
import "ag-grid-root/dist/styles/theme-fresh.css";
|
||||
|
||||
import fxData from "./reducers/fxData";
|
||||
import StoreService from './services/StoreService';
|
||||
import TraderDashboard from "./components/TraderDashboard.jsx";
|
||||
|
||||
let store = createStore(fxData);
|
||||
let store = StoreService.STORE;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
render(
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default (state = {fxRowData: []}, action) => {
|
||||
return state;
|
||||
};
|
||||
16
src-trader-dashboard/reducers/fxDataReducer.jsx
Normal file
@@ -0,0 +1,16 @@
|
||||
export default (state = {fxData: [], fxTopMovers: []}, action) => {
|
||||
switch (action.type) {
|
||||
case 'FX_DATA_CHANGED':
|
||||
return {
|
||||
...state,
|
||||
fxData: action.fxData.slice(0),
|
||||
};
|
||||
case 'FX_TOP_MOVERS_CHANGED':
|
||||
return {
|
||||
...state,
|
||||
fxTopMovers: action.fxTopMovers.slice(0),
|
||||
};
|
||||
default:
|
||||
return action.state;
|
||||
}
|
||||
};
|
||||
@@ -8,19 +8,49 @@ import keys from "lodash/keys";
|
||||
export default class {
|
||||
constructor() {
|
||||
this.subscribers = {};
|
||||
|
||||
this.exchanges = [
|
||||
{name: 'Nasdaq Stock Market', symbol: 'NASDAQ', supportedStocks: NASDAQ_SYMBOLS},
|
||||
{name: 'London Stock Exchange', symbol: 'LSE', supportedStocks: LSE_SYMBOLS},
|
||||
{name: 'Japan Exchange Group', symbol: 'JSE', supportedStocks: JSE_SYMBOLS},
|
||||
{name: 'Deutsche Börse', symbol: 'DE', supportedStocks: DE_SYMBOLS}
|
||||
];
|
||||
|
||||
this.initialiseTickerData();
|
||||
|
||||
this.timestamp = new Date();
|
||||
|
||||
// create the initial state of data
|
||||
this.initialiseTickerData();
|
||||
}
|
||||
|
||||
addSubscriber(subscriber, symbol) {
|
||||
if (!this.subscribers[symbol]) {
|
||||
this.subscribers[symbol] = [];
|
||||
}
|
||||
this.subscribers[symbol].push(subscriber);
|
||||
|
||||
if (!this.updateInterval) {
|
||||
this.updateInterval = setInterval(this.applyDeltasToTickerData.bind(this), 500);
|
||||
}
|
||||
}
|
||||
|
||||
removeSubscriber(subscriber, symbol) {
|
||||
remove(this.subscribers[symbol], subscriber);
|
||||
}
|
||||
|
||||
getTicker(symbol) {
|
||||
return this.tickerData[symbol];
|
||||
}
|
||||
|
||||
getExchanges() {
|
||||
return EXCHANGES;
|
||||
}
|
||||
|
||||
getExchangeInformation(exchangeName) {
|
||||
return find(EXCHANGES, (exchange) => {
|
||||
return exchange.symbol === exchangeName;
|
||||
})
|
||||
}
|
||||
|
||||
getTickerDetail(symbol) {
|
||||
return this.createTickerDetail(symbol);
|
||||
}
|
||||
|
||||
/*
|
||||
* the rest of this class exists primarily to create mock data - it can safely be ignored
|
||||
* as it is secondary to the main ideas being demonstrated by the rest of the application
|
||||
*/
|
||||
initialiseTickerData() {
|
||||
this.tickerData = {};
|
||||
|
||||
@@ -37,7 +67,7 @@ export default class {
|
||||
price,
|
||||
bid: price - this.random(1, 3),
|
||||
ask: price + this.random(1, 3),
|
||||
recommendation: ['Buy','Hold','Sell'][Math.floor(this.random(0, 2))]
|
||||
recommendation: ['Buy', 'Hold', 'Sell'][Math.floor(this.random(0, 2))]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,17 +75,6 @@ export default class {
|
||||
return parseFloat((Math.random() * (max - min + 1) + min))
|
||||
}
|
||||
|
||||
addSubscriber(subscriber, symbol) {
|
||||
if (!this.subscribers[symbol]) {
|
||||
this.subscribers[symbol] = [];
|
||||
}
|
||||
this.subscribers[symbol].push(subscriber);
|
||||
|
||||
if (!this.updateInterval) {
|
||||
this.updateInterval = setInterval(this.applyDeltasToTickerData.bind(this), 500);
|
||||
}
|
||||
}
|
||||
|
||||
applyDeltasToTickerData() {
|
||||
let symbols = keys(this.subscribers);
|
||||
let properties = ['price', 'bid', 'ask'];
|
||||
@@ -81,24 +100,6 @@ export default class {
|
||||
});
|
||||
}
|
||||
|
||||
removeSubscriber(subscriber, symbol) {
|
||||
remove(this.subscribers[symbol], subscriber);
|
||||
}
|
||||
|
||||
getTicker(symbol) {
|
||||
return this.tickerData[symbol];
|
||||
}
|
||||
|
||||
getExchanges() {
|
||||
return this.exchanges;
|
||||
}
|
||||
|
||||
getExchangeInformation(exchangeName) {
|
||||
return find(this.exchanges, (exchange) => {
|
||||
return exchange.symbol === exchangeName;
|
||||
})
|
||||
}
|
||||
|
||||
formatNumber(input) {
|
||||
return input.toFixed(2);
|
||||
}
|
||||
@@ -107,7 +108,7 @@ export default class {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
getTickerDetail(symbol) {
|
||||
createTickerDetail(symbol) {
|
||||
let ticker = this.getTicker(symbol);
|
||||
let currentPrice = ticker.price;
|
||||
let tenthOfCurrentPrice = currentPrice / 10;
|
||||
@@ -190,33 +191,6 @@ export default class {
|
||||
|
||||
return historicalData;
|
||||
}
|
||||
|
||||
getFxMatrixHeaderNames() {
|
||||
return FX_DELTA_HEADERS;
|
||||
}
|
||||
|
||||
getFxMatrixSnapshot() {
|
||||
let columns = FX_CURRENCY_MATRIX[0];
|
||||
let data = FX_CURRENCY_MATRIX.slice(1);
|
||||
|
||||
let rowData = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let currentRow = data[i];
|
||||
|
||||
let row = {};
|
||||
for (let j = 0; j < columns.length; j++) {
|
||||
row[columns[j]] = currentRow[j];
|
||||
}
|
||||
|
||||
// last, net and % change are different
|
||||
row['last'] = Math.floor(this.random(7000, 170000));
|
||||
row['net'] = this.random(-500, 500).toFixed(2);
|
||||
row['pct_net_change'] = this.random(-1, 1).toFixed(2);
|
||||
|
||||
rowData.push(row);
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
}
|
||||
|
||||
const NASDAQ_SYMBOLS = [
|
||||
@@ -355,348 +329,9 @@ const DE_SYMBOLS = [
|
||||
"AFMF.L",
|
||||
];
|
||||
|
||||
const FX_CURRENCY_SYMBOLS = ["USDGBP", "USDEUR", "USDAED", "USDJPY", "USDCAD", "USDCHF", "GBPUSD", "GBPEUR", "GBPAED", "GBPJPY", "GBPCAD", "GBPCHF", "EURUSD", "EURGBP", "EURAED", "EURJPY", "EURCAD", "EURCHF", "AEDUSD", "AEDGBP", "AEDEUR", "AEDJPY", "AEDCAD", "AEDCHF", "JPYUSD", "JPYGBP", "JPYEUR", "JPYAED", "JPYCAD", "JPYCHF", "CADUSD", "CADGBP", "CADEUR", "CADAED", "CADJPY", "CADCHF", "CHFUSD", "CHFGBP", "CHFEUR", "CHFAED", "CHFJPY", "CHFCAD"];
|
||||
const FX_DELTA_HEADERS = [
|
||||
{
|
||||
field: 'symbol',
|
||||
headerName: 'Symbol',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
field: 'last',
|
||||
headerName: 'Last',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right',
|
||||
width: 70
|
||||
},
|
||||
{
|
||||
field: 'net',
|
||||
headerName: 'Net',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellStyle: {'text-align': 'right'},
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
field: 'pct_net_change',
|
||||
headerName: '% NC',
|
||||
headerClass: 'align-right',
|
||||
cellStyle: {'text-align': 'right'}, // to be removed once the component is in place
|
||||
// cellRendererFramework: HorizontalBarComponent,
|
||||
width: 67,
|
||||
cellClassRules: {
|
||||
'pct-change-green': 'x > 0',
|
||||
'pct-change-amber': 'x <= 0 && x >= -0.10',
|
||||
'pct-change-red': 'x < -0.10'
|
||||
}
|
||||
},
|
||||
].concat(FX_CURRENCY_SYMBOLS.map((symbol) => {
|
||||
"use strict";
|
||||
return {
|
||||
field: symbol,
|
||||
headerName: symbol,
|
||||
headerClass: 'align-right',
|
||||
width: 87,
|
||||
cellStyle: {'text-align': 'right'},
|
||||
cellClassRules: {
|
||||
'fx-postive': 'x > 0.8',
|
||||
'fx-null': 'x === null',
|
||||
'fx-negative': 'x < -0.8'
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const FX_CURRENCY_MATRIX = [
|
||||
["symbol", ...FX_CURRENCY_SYMBOLS],
|
||||
["USDGBP", null, "0.89", "-0.01", "0.29", "0.28", "-0.04", "0.47", "0.17", "0.20", "0.11", "0.97", "0.07", "-0.20", "0.57", "0.54", "0.26", "0.33", "0.86", "0.95", "0.39", "0.21", "-0.49", "0.63", "-0.13", "-0.86", "0.18", "-0.84", "-0.89", "0.05", "-0.29", "0.34", "0.93", "0.41", "0.13", "-0.17", "0.70", "-0.17", "0.60", "0.00", "0.09", "-0.15", "0.10"],
|
||||
["USDEUR", "0.89", null, "0.25", "0.29", "0.86", "-0.93", "0.09", "0.63", "0.76", "0.10", "0.51", "-0.31", "-0.51", "0.20", "0.48", "-0.42", "0.73", "0.57", "0.65", "0.40", "0.12", "0.24", "0.42", "0.75", "0.13", "0.75", "0.42", "-0.80", "-0.26", "0.68", "0.68", "0.98", "0.87", "0.48", "0.52", "0.23", "0.61", "0.71", "-0.61", "0.40", "-0.80", "-0.89"],
|
||||
["USDAED", "0.90", "0.95", null, "0.71", "0.49", "0.50", "0.51", "0.07", "0.80", "-0.74", "0.54", "0.46", "-0.90", "-0.33", "0.75", "0.91", "0.84", "0.86", "0.89", "0.68", "0.71", "0.74", "0.58", "-0.24", "0.31", "0.85", "0.28", "0.44", "0.51", "-0.19", "0.71", "0.81", "0.85", "0.23", "0.09", "0.65", "-0.48", "0.43", "0.97", "0.11", "-0.81", "-0.69"],
|
||||
["USDJPY", "0.84", "0.92", "0.36", null, "0.79", "0.90", "0.86", "0.42", "0.14", "0.98", "0.47", "0.76", "0.60", "0.15", "0.04", "0.58", "0.13", "-0.16", "0.63", "0.86", "-0.63", "-0.95", "0.42", "0.08", "0.90", "-0.39", "-0.16", "0.66", "0.95", "0.31", "0.66", "-0.84", "0.06", "-0.60", "0.08", "0.57", "0.93", "0.78", "0.15", "0.36", "0.78", "0.34"],
|
||||
["USDCAD", "0.79", "-0.87", "0.93", "0.83", null, "0.10", "0.60", "0.34", "0.98", "0.70", "0.09", "0.46", "0.80", "0.10", "0.26", "-0.90", "0.69", "-0.22", "0.51", "-0.75", "-0.08", "0.07", "0.24", "0.68", "0.60", "0.37", "0.92", "0.02", "0.66", "0.16", "0.24", "-0.79", "0.19", "0.19", "0.08", "-0.97", "-0.93", "0.04", "-0.92", "0.86", "-0.36", "0.04"],
|
||||
["USDCHF", "0.94", "-0.02", "0.70", "0.82", "0.41", null, "0.76", "0.06", "0.46", "0.99", "0.07", "0.72", "0.14", "0.90", "0.23", "-0.54", "0.64", "0.80", "0.16", "0.23", "0.66", "-0.89", "-0.54", "-0.95", "0.27", "0.56", "0.42", "0.41", "0.88", "0.81", "0.37", "0.75", "0.06", "-0.75", "0.98", "0.21", "0.01", "0.03", "0.35", "-0.42", "0.55", "0.19"],
|
||||
["GBPUSD", "0.05", "-0.64", "0.47", "0.56", "0.51", "-0.47", null, "-0.15", "0.13", "0.55", "0.58", "0.57", "-0.49", "0.28", "0.86", "0.49", "0.12", "-0.91", "0.06", "0.12", "0.18", "-0.02", "-0.55", "0.18", "0.29", "0.76", "0.11", "0.04", "0.55", "0.16", "0.84", "0.83", "-0.94", "0.32", "0.07", "-0.33", "-0.29", "0.01", "-0.19", "0.01", "-0.60", "0.66"],
|
||||
["GBPEUR", "-0.32", "0.17", "0.60", "-0.52", "-0.52", "0.39", "-0.42", null, "0.07", "0.69", "0.67", "0.01", "0.72", "0.35", "0.66", "-0.66", "0.21", "0.12", "0.42", "-0.57", "-0.04", "0.48", "0.91", "0.72", "-0.16", "0.79", "0.03", "0.44", "0.17", "0.87", "-0.82", "0.20", "0.88", "0.48", "0.59", "-0.70", "0.12", "0.56", "-0.69", "0.10", "0.90", "1.00"],
|
||||
["GBPAED", "0.76", "0.05", "0.72", "-0.40", "0.93", "0.64", "0.90", "0.21", null, "0.91", "0.33", "-0.36", "0.28", "0.87", "0.25", "0.33", "0.44", "0.89", "0.17", "0.96", "0.86", "0.88", "0.03", "-0.25", "0.21", "0.98", "-0.60", "0.07", "0.90", "0.23", "0.41", "0.77", "0.83", "0.94", "0.12", "0.37", "0.58", "0.35", "-0.53", "0.49", "0.96", "-0.06"],
|
||||
["GBPJPY", "0.63", "0.72", "0.59", "0.89", "-0.54", "0.97", "0.61", "0.64", "0.85", null, "0.35", "0.57", "0.25", "0.85", "0.27", "-0.70", "-0.30", "-0.36", "0.29", "0.82", "0.26", "0.69", "0.46", "0.01", "0.09", "0.78", "0.95", "0.16", "0.07", "0.41", "0.99", "0.67", "0.34", "-0.89", "0.83", "0.32", "0.21", "-0.48", "-0.64", "0.65", "0.58", "0.69"],
|
||||
["GBPCAD", "0.78", "0.09", "0.33", "0.11", "0.95", "0.01", "0.96", "0.72", "0.13", "0.02", null, "0.44", "0.63", "-0.52", "0.08", "-0.85", "0.74", "0.41", "0.52", "0.15", "-0.97", "0.61", "0.58", "0.47", "0.56", "0.37", "0.54", "-0.65", "0.98", "0.44", "0.28", "0.70", "0.44", "0.34", "0.95", "0.82", "-0.09", "0.62", "0.87", "0.25", "-1.00", "0.99"],
|
||||
["GBPCHF", "-0.87", "0.68", "0.84", "0.83", "0.50", "0.74", "0.02", "0.11", "-0.12", "0.36", "0.71", null, "0.45", "0.02", "0.51", "0.50", "-0.03", "-0.94", "0.23", "0.38", "0.09", "0.26", "0.14", "0.39", "0.36", "0.01", "0.76", "0.21", "0.03", "0.97", "-0.89", "0.68", "0.43", "0.43", "0.26", "0.01", "0.60", "0.15", "0.77", "0.51", "-0.31", "0.37"],
|
||||
["EURUSD", "-0.45", "-0.05", "0.14", "-0.11", "0.36", "0.12", "0.76", "0.66", "0.50", "0.31", "0.28", "0.90", null, "-0.04", "0.73", "0.33", "0.27", "0.22", "0.86", "0.79", "-0.29", "0.30", "0.89", "0.73", "0.94", "0.24", "0.19", "0.81", "0.88", "0.46", "0.19", "0.79", "-0.16", "0.85", "0.84", "-0.57", "-0.87", "0.86", "0.69", "0.12", "0.64", "0.13"],
|
||||
["EURGBP", "0.06", "0.81", "0.54", "0.57", "0.57", "0.81", "0.38", "0.70", "0.37", "0.58", "-0.56", "0.77", "0.59", null, "0.98", "-0.48", "0.60", "0.78", "0.22", "0.20", "-0.62", "-0.97", "-0.55", "0.39", "0.88", "0.96", "0.32", "0.84", "0.26", "-0.47", "0.04", "0.34", "-0.24", "0.53", "-0.75", "-0.97", "0.47", "0.81", "0.49", "-0.84", "0.94", "0.09"],
|
||||
["EURAED", "0.61", "0.59", "0.11", "0.21", "0.41", "-0.45", "0.32", "0.90", "-0.98", "0.38", "0.27", "0.62", "0.67", "0.89", null, "0.27", "0.65", "0.72", "0.69", "0.66", "0.12", "0.32", "0.11", "-0.73", "-0.17", "0.74", "0.03", "0.96", "0.59", "-0.92", "-0.91", "-0.41", "0.09", "0.45", "0.90", "0.88", "0.96", "0.47", "0.95", "0.27", "-0.48", "0.71"],
|
||||
["EURJPY", "-0.01", "0.36", "0.28", "0.68", "0.50", "0.25", "0.81", "0.64", "0.12", "-0.73", "-0.47", "0.96", "-0.98", "-0.41", "0.78", null, "0.19", "-0.37", "0.24", "0.63", "0.74", "-0.24", "0.46", "0.63", "0.99", "0.65", "0.52", "0.11", "0.52", "0.39", "0.41", "0.51", "0.78", "1.00", "0.80", "-0.11", "0.90", "0.96", "0.66", "0.32", "0.02", "0.19"],
|
||||
["EURCAD", "-0.80", "0.40", "0.35", "0.45", "0.66", "0.21", "0.77", "0.58", "0.09", "1.00", "0.02", "-0.85", "0.89", "0.63", "-0.05", "0.46", null, "0.87", "0.96", "-0.48", "0.40", "0.18", "0.37", "0.81", "0.50", "-0.06", "-0.56", "0.38", "0.02", "0.83", "-0.93", "0.80", "0.31", "0.10", "0.70", "0.55", "0.47", "0.77", "0.98", "0.88", "0.19", "0.91"],
|
||||
["EURCHF", "-0.93", "0.01", "-0.29", "0.46", "-0.59", "-0.15", "0.58", "0.00", "-0.62", "0.36", "0.27", "-0.10", "-0.10", "0.57", "0.57", "0.75", "-0.10", null, "0.88", "0.21", "0.89", "0.85", "0.16", "0.93", "0.60", "0.59", "0.42", "0.70", "0.66", "0.80", "0.83", "0.52", "0.01", "0.41", "0.68", "0.94", "0.81", "0.40", "0.69", "0.04", "0.70", "0.61"],
|
||||
["AEDUSD", "0.10", "0.45", "0.06", "-0.37", "-0.14", "0.63", "0.10", "0.77", "0.95", "-0.12", "1.00", "-0.19", "-0.59", "0.78", "0.10", "0.76", "-0.45", "-0.99", null, "-0.46", "0.28", "0.31", "0.32", "0.42", "-0.00", "0.66", "0.24", "0.31", "0.10", "0.73", "0.02", "0.78", "0.07", "1.00", "0.43", "0.61", "0.53", "0.53", "0.41", "0.37", "0.97", "-0.19"],
|
||||
["AEDGBP", "0.70", "0.73", "0.34", "0.97", "0.84", "0.05", "0.21", "0.14", "0.45", "0.69", "0.41", "-0.53", "0.28", "0.13", "0.99", "0.97", "0.93", "0.62", "0.35", null, "0.18", "0.96", "0.58", "0.04", "0.00", "0.58", "-0.54", "0.35", "0.84", "0.83", "-0.20", "0.51", "0.32", "0.01", "0.95", "0.69", "-0.73", "0.36", "0.78", "0.02", "0.22", "0.39"],
|
||||
["AEDEUR", "0.18", "0.84", "-0.89", "0.90", "-0.25", "0.53", "0.71", "0.80", "0.60", "-0.98", "-0.81", "0.57", "0.72", "0.32", "-0.23", "0.98", "0.50", "0.93", "0.56", "0.26", null, "0.61", "0.47", "0.72", "0.58", "0.19", "0.94", "0.21", "0.47", "0.70", "0.67", "0.85", "0.98", "0.15", "0.21", "0.43", "0.03", "0.92", "0.91", "0.35", "0.70", "0.85"],
|
||||
["AEDJPY", "0.88", "0.62", "0.50", "0.27", "0.56", "0.61", "0.06", "-0.02", "0.42", "0.26", "0.23", "0.83", "-0.55", "0.94", "0.01", "0.72", "-0.43", "0.10", "0.01", "-0.20", "0.13", null, "0.70", "0.10", "0.05", "0.43", "-0.14", "-0.64", "0.80", "0.79", "0.57", "0.14", "0.14", "0.04", "-0.96", "0.59", "0.14", "0.51", "0.23", "0.57", "0.94", "0.88"],
|
||||
["AEDCAD", "0.75", "-0.99", "0.82", "-0.87", "0.79", "1.00", "0.21", "0.30", "-0.40", "0.34", "-0.85", "0.41", "0.79", "0.17", "0.58", "-0.24", "0.18", "0.15", "0.18", "0.44", "0.34", "0.90", null, "0.10", "0.34", "0.31", "0.34", "0.79", "-0.05", "0.19", "-0.86", "0.61", "-0.65", "0.23", "0.59", "0.69", "-0.65", "0.89", "0.97", "0.12", "0.63", "-0.24"],
|
||||
["AEDCHF", "0.67", "0.46", "0.92", "0.22", "0.91", "0.67", "0.81", "0.04", "0.29", "0.13", "0.80", "0.95", "0.29", "0.99", "-0.17", "0.58", "0.64", "0.68", "0.41", "0.69", "0.84", "0.01", "0.04", null, "0.07", "0.16", "0.26", "-0.43", "0.08", "0.58", "0.33", "-0.28", "0.03", "-0.08", "0.54", "-0.91", "0.78", "-0.10", "-0.13", "0.15", "0.62", "-0.13"],
|
||||
["JPYUSD", "-0.67", "0.90", "0.84", "0.10", "0.77", "0.43", "0.59", "0.69", "0.63", "0.82", "-0.61", "0.41", "0.07", "0.48", "1.00", "-0.52", "0.22", "0.89", "0.43", "0.54", "0.56", "-0.43", "0.78", "0.67", null, "0.06", "0.28", "0.04", "0.62", "0.18", "0.77", "0.63", "0.05", "0.87", "0.22", "0.21", "0.07", "0.25", "-0.55", "0.67", "0.10", "-0.67"],
|
||||
["JPYGBP", "0.21", "0.46", "0.23", "0.53", "-0.97", "0.78", "0.43", "0.74", "-0.95", "0.98", "0.49", "0.66", "0.18", "0.55", "-0.33", "0.67", "0.65", "0.23", "-0.07", "-0.67", "0.56", "0.74", "-0.38", "-0.83", "-0.51", null, "-0.26", "-0.79", "0.73", "-0.78", "-0.09", "0.19", "0.48", "0.97", "0.11", "0.19", "0.51", "0.32", "0.81", "-0.02", "0.17", "0.48"],
|
||||
["JPYEUR", "0.83", "0.86", "0.62", "-0.92", "0.64", "0.58", "0.55", "0.07", "0.81", "0.32", "0.33", "0.96", "0.48", "0.57", "0.25", "0.56", "0.33", "0.02", "-0.79", "0.44", "0.95", "0.35", "0.41", "0.06", "0.28", "0.77", null, "0.64", "0.79", "0.74", "0.67", "-0.97", "0.47", "-0.11", "0.03", "0.39", "-0.37", "0.06", "0.09", "0.13", "0.20", "0.87"],
|
||||
["JPYAED", "0.69", "0.80", "0.90", "0.06", "0.55", "0.90", "-0.09", "0.05", "-0.10", "0.31", "0.57", "0.69", "-0.78", "0.42", "0.64", "0.96", "0.08", "-0.76", "0.59", "0.00", "0.40", "-0.88", "0.69", "0.17", "-0.16", "0.57", "0.86", null, "-0.61", "-0.14", "0.41", "-0.16", "0.36", "0.95", "0.44", "0.41", "0.35", "-0.56", "0.25", "0.66", "0.90", "0.82"],
|
||||
["JPYCAD", "0.33", "0.27", "0.61", "0.01", "-0.16", "0.21", "0.57", "-0.41", "-0.56", "0.55", "0.13", "-0.87", "0.19", "0.64", "-0.38", "-0.80", "-0.10", "0.44", "0.72", "-0.72", "0.48", "0.42", "0.84", "0.73", "0.35", "0.68", "0.01", "0.09", null, "0.87", "0.17", "0.45", "0.02", "0.01", "0.77", "0.24", "0.62", "0.39", "-0.73", "0.21", "-0.08", "0.42"],
|
||||
["JPYCHF", "-0.45", "0.52", "0.34", "0.85", "0.16", "0.96", "0.53", "0.62", "0.46", "0.94", "0.08", "-0.68", "0.81", "0.44", "0.27", "0.75", "-0.84", "0.69", "-0.99", "0.41", "0.66", "-0.94", "0.21", "0.85", "-0.08", "0.36", "0.62", "0.25", "-0.48", null, "0.51", "-0.39", "0.60", "0.63", "0.68", "0.10", "0.62", "0.68", "0.00", "0.24", "0.61", "0.23"],
|
||||
["CADUSD", "-0.65", "0.73", "0.93", "0.27", "-0.00", "-0.46", "0.53", "0.36", "0.83", "0.58", "0.40", "0.03", "0.32", "0.38", "-0.53", "0.86", "0.42", "0.90", "0.83", "0.94", "0.34", "-0.56", "0.46", "-0.72", "0.13", "0.08", "0.25", "0.59", "0.75", "0.72", null, "0.62", "0.73", "0.52", "0.28", "0.03", "-0.54", "0.50", "0.76", "-0.28", "0.89", "0.97"],
|
||||
["CADGBP", "0.74", "0.58", "0.55", "0.01", "0.33", "0.61", "0.75", "0.86", "-0.87", "0.50", "0.57", "0.84", "-0.34", "1.00", "0.77", "0.75", "0.40", "0.12", "-0.57", "-0.16", "-0.91", "0.06", "0.67", "-0.55", "0.02", "0.78", "0.57", "0.70", "0.21", "0.95", "-0.91", null, "-0.82", "0.71", "0.36", "0.46", "0.46", "0.24", "0.15", "0.54", "0.15", "0.83"],
|
||||
["CADEUR", "-0.58", "0.29", "0.03", "0.70", "0.77", "0.80", "0.52", "0.04", "0.11", "0.86", "-0.98", "0.02", "0.01", "-0.19", "-0.48", "0.80", "0.90", "0.10", "0.28", "0.88", "0.98", "0.43", "0.47", "-0.41", "-0.92", "0.49", "0.64", "-0.60", "0.11", "0.61", "0.19", "-0.39", null, "-0.21", "0.56", "-0.45", "-0.48", "0.51", "0.04", "-0.44", "-0.22", "-0.29"],
|
||||
["CADAED", "0.07", "0.55", "0.99", "-0.41", "0.65", "0.75", "0.97", "0.74", "0.65", "0.37", "-0.04", "0.85", "0.83", "0.25", "0.14", "-0.00", "0.80", "0.78", "-0.42", "0.54", "-0.42", "-0.07", "-0.62", "0.56", "0.89", "0.92", "0.19", "0.64", "0.45", "0.24", "0.97", "0.41", "0.36", null, "-0.54", "-0.85", "-0.68", "0.48", "0.13", "0.61", "0.75", "0.21"],
|
||||
["CADJPY", "-0.84", "0.71", "0.59", "-0.78", "0.92", "0.93", "0.03", "0.27", "0.22", "0.71", "-0.79", "0.72", "0.27", "0.29", "0.40", "0.66", "0.44", "-0.33", "0.24", "0.99", "-0.95", "0.74", "0.42", "0.45", "0.08", "0.46", "0.22", "0.70", "0.80", "0.36", "0.36", "0.94", "0.75", "0.51", null, "0.10", "0.31", "0.54", "1.00", "0.78", "0.17", "0.32"],
|
||||
["CADCHF", "0.19", "0.00", "0.62", "-0.63", "0.75", "0.57", "0.28", "-0.98", "0.17", "-0.63", "0.09", "0.10", "-0.09", "0.22", "0.65", "0.20", "0.27", "-0.66", "-0.70", "0.72", "0.40", "0.96", "0.52", "0.38", "0.96", "0.90", "0.35", "-0.70", "0.37", "0.94", "0.20", "0.78", "0.34", "0.24", "-0.18", null, "0.05", "0.71", "0.05", "0.38", "0.02", "0.60"],
|
||||
["CHFUSD", "0.42", "0.61", "-0.30", "-0.27", "0.46", "0.63", "0.64", "0.33", "0.18", "0.88", "0.99", "0.73", "0.85", "0.07", "0.53", "0.31", "-0.63", "0.56", "-0.04", "-0.68", "0.43", "-0.96", "0.45", "0.45", "0.50", "0.17", "0.82", "0.34", "0.26", "0.16", "0.71", "0.35", "0.57", "0.79", "0.56", "0.55", null, "0.02", "-0.90", "0.84", "0.33", "0.18"],
|
||||
["CHFGBP", "-0.38", "0.73", "0.25", "0.64", "0.41", "-0.48", "0.75", "-0.40", "0.37", "0.62", "0.30", "0.06", "0.54", "0.15", "0.51", "0.33", "-0.79", "-0.05", "-0.54", "0.21", "0.40", "0.86", "0.96", "0.94", "0.52", "0.07", "0.71", "-0.80", "-0.40", "0.71", "0.71", "0.89", "0.43", "-0.68", "0.93", "0.05", "0.42", null, "0.59", "-0.67", "0.03", "0.17"],
|
||||
["CHFEUR", "-0.64", "0.96", "-0.34", "0.71", "0.53", "0.44", "0.27", "0.56", "0.96", "0.40", "0.86", "0.65", "0.82", "0.89", "-0.75", "0.29", "0.06", "0.70", "0.23", "0.68", "0.79", "0.21", "0.50", "0.14", "-0.27", "-0.83", "-0.22", "0.59", "0.40", "0.10", "0.88", "0.99", "0.21", "-0.36", "0.00", "0.53", "0.08", "0.08", null, "0.53", "-0.51", "0.03"],
|
||||
["CHFAED", "-0.99", "0.71", "0.51", "0.58", "0.57", "0.73", "0.60", "0.23", "0.02", "0.84", "0.90", "0.56", "0.03", "-0.93", "0.59", "0.24", "-0.67", "0.13", "0.99", "0.28", "0.72", "0.79", "-0.83", "-0.30", "0.73", "0.08", "-0.02", "0.85", "0.33", "0.57", "0.09", "0.26", "0.16", "0.80", "0.65", "-0.19", "-0.38", "-0.61", "-0.98", null, "0.57", "-0.81"],
|
||||
["CHFJPY", "0.60", "0.96", "0.22", "0.52", "0.63", "0.24", "0.76", "0.91", "0.80", "-0.14", "0.59", "-0.01", "0.60", "-0.08", "0.63", "0.39", "0.30", "-0.71", "0.18", "0.94", "-0.30", "0.28", "0.87", "0.92", "-0.19", "0.18", "-0.40", "0.44", "0.88", "0.52", "0.50", "0.44", "0.84", "0.24", "0.09", "0.15", "0.10", "0.30", "-0.05", "0.79", null, "0.99"],
|
||||
["CHFCAD", "0.93", "0.24", "0.05", "0.40", "0.75", "0.12", "0.90", "0.56", "0.46", "0.62", "0.71", "0.01", "0.04", "0.02", "0.49", "0.51", "-0.94", "0.93", "0.80", "-0.40", "0.79", "0.82", "-0.04", "0.38", "-0.24", "-0.17", "0.78", "-0.42", "0.92", "-0.83", "-0.01", "0.54", "0.73", "0.52", "0.95", "0.44", "0.90", "0.81", "0.42", "0.26", "0.36", null]
|
||||
const EXCHANGES = [
|
||||
{name: 'Nasdaq Stock Market', symbol: 'NASDAQ', supportedStocks: NASDAQ_SYMBOLS},
|
||||
{name: 'London Stock Exchange', symbol: 'LSE', supportedStocks: LSE_SYMBOLS},
|
||||
{name: 'Japan Exchange Group', symbol: 'JSE', supportedStocks: JSE_SYMBOLS},
|
||||
{name: 'Deutsche Börse', symbol: 'DE', supportedStocks: DE_SYMBOLS}
|
||||
];
|
||||
|
||||
// for (i = 0; i < MAJOR_CURRENCIES.length; i++) {
|
||||
// for (j = 0; j < MAJOR_CURRENCIES.length; j++) {
|
||||
// if (i === j) {
|
||||
// continue;
|
||||
// }
|
||||
// console.log(`${MAJOR_CURRENCIES[i] + MAJOR_CURRENCIES[j]}`);
|
||||
// }
|
||||
// }
|
||||
|
||||
// let rows = [];
|
||||
// let row = ['Symbol'];
|
||||
//
|
||||
// rows = [];
|
||||
// for (j = 0; j < FX_CURRENCY_CODE.length; j++) {
|
||||
// row.push(FX_CURRENCY_CODE[j]);
|
||||
// }
|
||||
// rows.push(row);
|
||||
//
|
||||
// for (i = 0; i < FX_CURRENCY_CODE.length; i++) {
|
||||
// let row = [];
|
||||
// row.push(FX_CURRENCY_CODE[i]);
|
||||
//
|
||||
// for (j = 0; j < FX_CURRENCY_CODE.length; j++) {
|
||||
// if (i === j) {
|
||||
// row.push(null);
|
||||
// } else {
|
||||
// var mutliplier = ((Math.random() * 10) > 8) ? -1 : 1;
|
||||
// row.push((mutliplier * Math.random()).toFixed(2))
|
||||
// // row.push(`${FX_CURRENCY_CODE[j]} value`)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// rows.push(row);
|
||||
// }
|
||||
//
|
||||
// JSON.stringify(rows);
|
||||
|
||||
const FX_CURRENCY_CODE = [
|
||||
'USDGBP',
|
||||
'USDEUR',
|
||||
'USDAED',
|
||||
'USDJPY',
|
||||
'USDCAD',
|
||||
'USDCHF',
|
||||
'GBPUSD',
|
||||
'GBPEUR',
|
||||
'GBPAED',
|
||||
'GBPJPY',
|
||||
'GBPCAD',
|
||||
'GBPCHF',
|
||||
'EURUSD',
|
||||
'EURGBP',
|
||||
'EURAED',
|
||||
'EURJPY',
|
||||
'EURCAD',
|
||||
'EURCHF',
|
||||
'AEDUSD',
|
||||
'AEDGBP',
|
||||
'AEDEUR',
|
||||
'AEDJPY',
|
||||
'AEDCAD',
|
||||
'AEDCHF',
|
||||
'JPYUSD',
|
||||
'JPYGBP',
|
||||
'JPYEUR',
|
||||
'JPYAED',
|
||||
'JPYCAD',
|
||||
'JPYCHF',
|
||||
'CADUSD',
|
||||
'CADGBP',
|
||||
'CADEUR',
|
||||
'CADAED',
|
||||
'CADJPY',
|
||||
'CADCHF',
|
||||
'CHFUSD',
|
||||
'CHFGBP',
|
||||
'CHFEUR',
|
||||
'CHFAED',
|
||||
'CHFJPY',
|
||||
'CHFCAD'
|
||||
];
|
||||
|
||||
const MAJOR_CURRENCIES = [
|
||||
'USD',
|
||||
'GBP',
|
||||
'EUR',
|
||||
'AED',
|
||||
'JPY',
|
||||
'CAD',
|
||||
'CHF'];
|
||||
|
||||
const SECONDARY_CURRENCIES = [
|
||||
'AFN',
|
||||
'ALL',
|
||||
'AMD',
|
||||
'ANG',
|
||||
'AOA',
|
||||
'ARS',
|
||||
'AUD',
|
||||
'AWG',
|
||||
'AZN',
|
||||
'BAM',
|
||||
'BBD',
|
||||
'BDT',
|
||||
'BGN',
|
||||
'BHD',
|
||||
'BIF',
|
||||
'BMD',
|
||||
'BND',
|
||||
'BOB',
|
||||
'BRL',
|
||||
'BSD',
|
||||
'BTN',
|
||||
'BWP',
|
||||
'BYN',
|
||||
'BZD',
|
||||
'CDF',
|
||||
'CLP',
|
||||
'CNY',
|
||||
'COP',
|
||||
'CRC',
|
||||
'CUC',
|
||||
'CUP',
|
||||
'CVE',
|
||||
'CZK',
|
||||
'DJF',
|
||||
'DKK',
|
||||
'DOP',
|
||||
'DZD',
|
||||
'EGP',
|
||||
'ERN',
|
||||
'ETB',
|
||||
'FJD',
|
||||
'FKP',
|
||||
'GEL',
|
||||
'GGP',
|
||||
'GHS',
|
||||
'GIP',
|
||||
'GMD',
|
||||
'GNF',
|
||||
'GTQ',
|
||||
'GYD',
|
||||
'HKD',
|
||||
'HNL',
|
||||
'HRK',
|
||||
'HTG',
|
||||
'HUF',
|
||||
'IDR',
|
||||
'ILS',
|
||||
'IMP',
|
||||
'INR',
|
||||
'IQD',
|
||||
'IRR',
|
||||
'ISK',
|
||||
'JEP',
|
||||
'JMD',
|
||||
'JOD',
|
||||
'KES',
|
||||
'KGS',
|
||||
'KHR',
|
||||
'KMF',
|
||||
'KPW',
|
||||
'KRW',
|
||||
'KWD',
|
||||
'KYD',
|
||||
'KZT',
|
||||
'LAK',
|
||||
'LBP',
|
||||
'LKR',
|
||||
'LRD',
|
||||
'LSL',
|
||||
'LYD',
|
||||
'MAD',
|
||||
'MDL',
|
||||
'MGA',
|
||||
'MKD',
|
||||
'MMK',
|
||||
'MNT',
|
||||
'MOP',
|
||||
'MRO',
|
||||
'MUR',
|
||||
'MVR',
|
||||
'MWK',
|
||||
'MXN',
|
||||
'MYR',
|
||||
'MZN',
|
||||
'NAD',
|
||||
'NGN',
|
||||
'NIO',
|
||||
'NOK',
|
||||
'NPR',
|
||||
'NZD',
|
||||
'OMR',
|
||||
'PAB',
|
||||
'PEN',
|
||||
'PGK',
|
||||
'PHP',
|
||||
'PKR',
|
||||
'PLN',
|
||||
'PYG',
|
||||
'QAR',
|
||||
'RON',
|
||||
'RSD',
|
||||
'RUB',
|
||||
'RWF',
|
||||
'SAR',
|
||||
'SBD',
|
||||
'SCR',
|
||||
'SDG',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'SHP',
|
||||
'SLL',
|
||||
'SOS',
|
||||
'SPL',
|
||||
'SRD',
|
||||
'STD',
|
||||
'SVC',
|
||||
'SYP',
|
||||
'SZL',
|
||||
'THB',
|
||||
'TJS',
|
||||
'TMT',
|
||||
'TND',
|
||||
'TOP',
|
||||
'TRY',
|
||||
'TTD',
|
||||
'TVD',
|
||||
'TWD',
|
||||
'TZS',
|
||||
'UAH',
|
||||
'UGX',
|
||||
'UYU',
|
||||
'UZS',
|
||||
'VEF',
|
||||
'VND',
|
||||
'VUV',
|
||||
'WST',
|
||||
'XAF',
|
||||
'XCD',
|
||||
'XDR',
|
||||
'XOF',
|
||||
'XPF',
|
||||
'YER',
|
||||
'ZMW',
|
||||
'ZWD',
|
||||
'ZAR'];
|
||||
|
||||
201
src-trader-dashboard/services/FxDataService.jsx
Normal file
@@ -0,0 +1,201 @@
|
||||
import sampleSize from "lodash/sampleSize";
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
|
||||
import StoreService from "./StoreService";
|
||||
import {fxDataUpdated, fxTopMoversUpdated} from "../actions/fxDataActions";
|
||||
|
||||
import HorizontalBarComponent from "../components/renderers/HorizontalBarComponent.jsx";
|
||||
|
||||
export default class {
|
||||
constructor() {
|
||||
this.store = StoreService.STORE;
|
||||
|
||||
// create the initial state of the fx data
|
||||
this.createFxMatrixSnapshot();
|
||||
this.calculateTopMovers();
|
||||
|
||||
// and dispatch it
|
||||
this.store.dispatch(fxDataUpdated(this.fxData));
|
||||
this.store.dispatch(fxTopMoversUpdated(this.fxTopMovers));
|
||||
|
||||
// periodically update the fx and top mover information
|
||||
this.kickOffPeriodicUpdates();
|
||||
}
|
||||
|
||||
kickOffPeriodicUpdates() {
|
||||
setInterval(() => {
|
||||
this.applyDeltasToFxData();
|
||||
|
||||
this.store.dispatch(fxDataUpdated(this.fxData));
|
||||
}, 1500);
|
||||
|
||||
setInterval(() => {
|
||||
this.calculateTopMovers();
|
||||
|
||||
this.store.dispatch(fxTopMoversUpdated(this.fxTopMovers));
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
/*
|
||||
* the rest of this class exists primarily to create mock data - it can safely be ignored
|
||||
* as it is secondary to the main ideas being demonstrated by the rest of the application
|
||||
*/
|
||||
calculateTopMovers() {
|
||||
let fxData = cloneDeep(this.fxData);
|
||||
fxData.sort((a, b) => {
|
||||
return Math.abs(b.pct_net_change) - Math.abs(a.pct_net_change);
|
||||
});
|
||||
|
||||
this.fxTopMovers = fxData.slice(0, 20);
|
||||
}
|
||||
|
||||
applyDeltasToFxData() {
|
||||
let fxSymbolsToUpdate = sampleSize(FX_CURRENCY_SYMBOLS, FX_CURRENCY_SYMBOLS.length / 5);
|
||||
let rowsToUpdate = sampleSize(this.fxData, this.fxData.length / 5);
|
||||
for (let i = 0; i < rowsToUpdate.length; i++) {
|
||||
let row = rowsToUpdate[i];
|
||||
|
||||
let maxSwing = row.last * 0.05; // max 5% swing
|
||||
let swing = Math.floor(this.random(-maxSwing, maxSwing));
|
||||
row.last = row.last + swing;
|
||||
row.net = swing;
|
||||
|
||||
let multiplier = ((Math.random() * 10) > 5) ? -1 : 1;
|
||||
row['pct_net_change'] = multiplier * (this.random(30, 100) / 100).toFixed(2);
|
||||
|
||||
for (let symbolToUpdate of fxSymbolsToUpdate) {
|
||||
if (row[symbolToUpdate] === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let multiplier = ((Math.random() * 10) > 8) ? -1 : 1;
|
||||
row[symbolToUpdate] = (multiplier * Math.random()).toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
random(min, max) {
|
||||
return parseFloat((Math.random() * (max - min + 1) + min))
|
||||
}
|
||||
|
||||
getFxMatrixHeaderNames() {
|
||||
return FX_DELTA_HEADERS;
|
||||
}
|
||||
|
||||
createFxMatrixSnapshot() {
|
||||
let columns = FX_CURRENCY_MATRIX[0];
|
||||
let data = FX_CURRENCY_MATRIX.slice(1);
|
||||
|
||||
let rowData = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let currentRow = data[i];
|
||||
|
||||
let row = {};
|
||||
for (let j = 0; j < columns.length; j++) {
|
||||
row[columns[j]] = currentRow[j];
|
||||
}
|
||||
|
||||
// last, net and % change are different
|
||||
row['last'] = Math.floor(this.random(7000, 170000));
|
||||
row['net'] = Math.floor(this.random(-500, 500));
|
||||
|
||||
let multiplier = ((Math.random() * 10) > 5) ? -1 : 1;
|
||||
row['pct_net_change'] = multiplier * (this.random(30, 100) / 100).toFixed(2);
|
||||
|
||||
rowData.push(row);
|
||||
}
|
||||
|
||||
this.fxData = rowData;
|
||||
}
|
||||
}
|
||||
|
||||
const FX_CURRENCY_SYMBOLS = ["USDGBP", "USDEUR", "USDAED", "USDJPY", "USDCAD", "USDCHF", "GBPUSD", "GBPEUR", "GBPAED", "GBPJPY", "GBPCAD", "GBPCHF", "EURUSD", "EURGBP", "EURAED", "EURJPY", "EURCAD", "EURCHF", "AEDUSD", "AEDGBP", "AEDEUR", "AEDJPY", "AEDCAD", "AEDCHF", "JPYUSD", "JPYGBP", "JPYEUR", "JPYAED", "JPYCAD", "JPYCHF", "CADUSD", "CADGBP", "CADEUR", "CADAED", "CADJPY", "CADCHF", "CHFUSD", "CHFGBP", "CHFEUR", "CHFAED", "CHFJPY", "CHFCAD"];
|
||||
const FX_DELTA_HEADERS = [
|
||||
{
|
||||
field: 'symbol',
|
||||
headerName: 'Symbol',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
field: 'last',
|
||||
headerName: 'Last',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
field: 'net',
|
||||
headerName: 'Net',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
field: 'pct_net_change',
|
||||
headerName: '% NC',
|
||||
cellRendererFramework: HorizontalBarComponent,
|
||||
width: 85
|
||||
},
|
||||
].concat(FX_CURRENCY_SYMBOLS.map((symbol) => {
|
||||
"use strict";
|
||||
return {
|
||||
field: symbol,
|
||||
headerName: symbol,
|
||||
width: 67,
|
||||
cellClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClassRules: {
|
||||
'fx-positive': 'x > 0.8',
|
||||
'fx-null': 'x === null',
|
||||
'fx-negative': 'x < -0.8'
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const FX_CURRENCY_MATRIX = [
|
||||
["symbol", ...FX_CURRENCY_SYMBOLS],
|
||||
["USDGBP", null, "0.89", "-0.01", "0.29", "0.28", "-0.04", "0.47", "0.17", "0.20", "0.11", "0.97", "0.07", "-0.20", "0.57", "0.54", "0.26", "0.33", "0.86", "0.95", "0.39", "0.21", "-0.49", "0.63", "-0.13", "-0.86", "0.18", "-0.84", "-0.89", "0.05", "-0.29", "0.34", "0.93", "0.41", "0.13", "-0.17", "0.70", "-0.17", "0.60", "0.00", "0.09", "-0.15", "0.10"],
|
||||
["USDEUR", "0.89", null, "0.25", "0.29", "0.86", "-0.93", "0.09", "0.63", "0.76", "0.10", "0.51", "-0.31", "-0.51", "0.20", "0.48", "-0.42", "0.73", "0.57", "0.65", "0.40", "0.12", "0.24", "0.42", "0.75", "0.13", "0.75", "0.42", "-0.80", "-0.26", "0.68", "0.68", "0.98", "0.87", "0.48", "0.52", "0.23", "0.61", "0.71", "-0.61", "0.40", "-0.80", "-0.89"],
|
||||
["USDAED", "0.90", "0.95", null, "0.71", "0.49", "0.50", "0.51", "0.07", "0.80", "-0.74", "0.54", "0.46", "-0.90", "-0.33", "0.75", "0.91", "0.84", "0.86", "0.89", "0.68", "0.71", "0.74", "0.58", "-0.24", "0.31", "0.85", "0.28", "0.44", "0.51", "-0.19", "0.71", "0.81", "0.85", "0.23", "0.09", "0.65", "-0.48", "0.43", "0.97", "0.11", "-0.81", "-0.69"],
|
||||
["USDJPY", "0.84", "0.92", "0.36", null, "0.79", "0.90", "0.86", "0.42", "0.14", "0.98", "0.47", "0.76", "0.60", "0.15", "0.04", "0.58", "0.13", "-0.16", "0.63", "0.86", "-0.63", "-0.95", "0.42", "0.08", "0.90", "-0.39", "-0.16", "0.66", "0.95", "0.31", "0.66", "-0.84", "0.06", "-0.60", "0.08", "0.57", "0.93", "0.78", "0.15", "0.36", "0.78", "0.34"],
|
||||
["USDCAD", "0.79", "-0.87", "0.93", "0.83", null, "0.10", "0.60", "0.34", "0.98", "0.70", "0.09", "0.46", "0.80", "0.10", "0.26", "-0.90", "0.69", "-0.22", "0.51", "-0.75", "-0.08", "0.07", "0.24", "0.68", "0.60", "0.37", "0.92", "0.02", "0.66", "0.16", "0.24", "-0.79", "0.19", "0.19", "0.08", "-0.97", "-0.93", "0.04", "-0.92", "0.86", "-0.36", "0.04"],
|
||||
["USDCHF", "0.94", "-0.02", "0.70", "0.82", "0.41", null, "0.76", "0.06", "0.46", "0.99", "0.07", "0.72", "0.14", "0.90", "0.23", "-0.54", "0.64", "0.80", "0.16", "0.23", "0.66", "-0.89", "-0.54", "-0.95", "0.27", "0.56", "0.42", "0.41", "0.88", "0.81", "0.37", "0.75", "0.06", "-0.75", "0.98", "0.21", "0.01", "0.03", "0.35", "-0.42", "0.55", "0.19"],
|
||||
["GBPUSD", "0.05", "-0.64", "0.47", "0.56", "0.51", "-0.47", null, "-0.15", "0.13", "0.55", "0.58", "0.57", "-0.49", "0.28", "0.86", "0.49", "0.12", "-0.91", "0.06", "0.12", "0.18", "-0.02", "-0.55", "0.18", "0.29", "0.76", "0.11", "0.04", "0.55", "0.16", "0.84", "0.83", "-0.94", "0.32", "0.07", "-0.33", "-0.29", "0.01", "-0.19", "0.01", "-0.60", "0.66"],
|
||||
["GBPEUR", "-0.32", "0.17", "0.60", "-0.52", "-0.52", "0.39", "-0.42", null, "0.07", "0.69", "0.67", "0.01", "0.72", "0.35", "0.66", "-0.66", "0.21", "0.12", "0.42", "-0.57", "-0.04", "0.48", "0.91", "0.72", "-0.16", "0.79", "0.03", "0.44", "0.17", "0.87", "-0.82", "0.20", "0.88", "0.48", "0.59", "-0.70", "0.12", "0.56", "-0.69", "0.10", "0.90", "1.00"],
|
||||
["GBPAED", "0.76", "0.05", "0.72", "-0.40", "0.93", "0.64", "0.90", "0.21", null, "0.91", "0.33", "-0.36", "0.28", "0.87", "0.25", "0.33", "0.44", "0.89", "0.17", "0.96", "0.86", "0.88", "0.03", "-0.25", "0.21", "0.98", "-0.60", "0.07", "0.90", "0.23", "0.41", "0.77", "0.83", "0.94", "0.12", "0.37", "0.58", "0.35", "-0.53", "0.49", "0.96", "-0.06"],
|
||||
["GBPJPY", "0.63", "0.72", "0.59", "0.89", "-0.54", "0.97", "0.61", "0.64", "0.85", null, "0.35", "0.57", "0.25", "0.85", "0.27", "-0.70", "-0.30", "-0.36", "0.29", "0.82", "0.26", "0.69", "0.46", "0.01", "0.09", "0.78", "0.95", "0.16", "0.07", "0.41", "0.99", "0.67", "0.34", "-0.89", "0.83", "0.32", "0.21", "-0.48", "-0.64", "0.65", "0.58", "0.69"],
|
||||
["GBPCAD", "0.78", "0.09", "0.33", "0.11", "0.95", "0.01", "0.96", "0.72", "0.13", "0.02", null, "0.44", "0.63", "-0.52", "0.08", "-0.85", "0.74", "0.41", "0.52", "0.15", "-0.97", "0.61", "0.58", "0.47", "0.56", "0.37", "0.54", "-0.65", "0.98", "0.44", "0.28", "0.70", "0.44", "0.34", "0.95", "0.82", "-0.09", "0.62", "0.87", "0.25", "-1.00", "0.99"],
|
||||
["GBPCHF", "-0.87", "0.68", "0.84", "0.83", "0.50", "0.74", "0.02", "0.11", "-0.12", "0.36", "0.71", null, "0.45", "0.02", "0.51", "0.50", "-0.03", "-0.94", "0.23", "0.38", "0.09", "0.26", "0.14", "0.39", "0.36", "0.01", "0.76", "0.21", "0.03", "0.97", "-0.89", "0.68", "0.43", "0.43", "0.26", "0.01", "0.60", "0.15", "0.77", "0.51", "-0.31", "0.37"],
|
||||
["EURUSD", "-0.45", "-0.05", "0.14", "-0.11", "0.36", "0.12", "0.76", "0.66", "0.50", "0.31", "0.28", "0.90", null, "-0.04", "0.73", "0.33", "0.27", "0.22", "0.86", "0.79", "-0.29", "0.30", "0.89", "0.73", "0.94", "0.24", "0.19", "0.81", "0.88", "0.46", "0.19", "0.79", "-0.16", "0.85", "0.84", "-0.57", "-0.87", "0.86", "0.69", "0.12", "0.64", "0.13"],
|
||||
["EURGBP", "0.06", "0.81", "0.54", "0.57", "0.57", "0.81", "0.38", "0.70", "0.37", "0.58", "-0.56", "0.77", "0.59", null, "0.98", "-0.48", "0.60", "0.78", "0.22", "0.20", "-0.62", "-0.97", "-0.55", "0.39", "0.88", "0.96", "0.32", "0.84", "0.26", "-0.47", "0.04", "0.34", "-0.24", "0.53", "-0.75", "-0.97", "0.47", "0.81", "0.49", "-0.84", "0.94", "0.09"],
|
||||
["EURAED", "0.61", "0.59", "0.11", "0.21", "0.41", "-0.45", "0.32", "0.90", "-0.98", "0.38", "0.27", "0.62", "0.67", "0.89", null, "0.27", "0.65", "0.72", "0.69", "0.66", "0.12", "0.32", "0.11", "-0.73", "-0.17", "0.74", "0.03", "0.96", "0.59", "-0.92", "-0.91", "-0.41", "0.09", "0.45", "0.90", "0.88", "0.96", "0.47", "0.95", "0.27", "-0.48", "0.71"],
|
||||
["EURJPY", "-0.01", "0.36", "0.28", "0.68", "0.50", "0.25", "0.81", "0.64", "0.12", "-0.73", "-0.47", "0.96", "-0.98", "-0.41", "0.78", null, "0.19", "-0.37", "0.24", "0.63", "0.74", "-0.24", "0.46", "0.63", "0.99", "0.65", "0.52", "0.11", "0.52", "0.39", "0.41", "0.51", "0.78", "1.00", "0.80", "-0.11", "0.90", "0.96", "0.66", "0.32", "0.02", "0.19"],
|
||||
["EURCAD", "-0.80", "0.40", "0.35", "0.45", "0.66", "0.21", "0.77", "0.58", "0.09", "1.00", "0.02", "-0.85", "0.89", "0.63", "-0.05", "0.46", null, "0.87", "0.96", "-0.48", "0.40", "0.18", "0.37", "0.81", "0.50", "-0.06", "-0.56", "0.38", "0.02", "0.83", "-0.93", "0.80", "0.31", "0.10", "0.70", "0.55", "0.47", "0.77", "0.98", "0.88", "0.19", "0.91"],
|
||||
["EURCHF", "-0.93", "0.01", "-0.29", "0.46", "-0.59", "-0.15", "0.58", "0.00", "-0.62", "0.36", "0.27", "-0.10", "-0.10", "0.57", "0.57", "0.75", "-0.10", null, "0.88", "0.21", "0.89", "0.85", "0.16", "0.93", "0.60", "0.59", "0.42", "0.70", "0.66", "0.80", "0.83", "0.52", "0.01", "0.41", "0.68", "0.94", "0.81", "0.40", "0.69", "0.04", "0.70", "0.61"],
|
||||
["AEDUSD", "0.10", "0.45", "0.06", "-0.37", "-0.14", "0.63", "0.10", "0.77", "0.95", "-0.12", "1.00", "-0.19", "-0.59", "0.78", "0.10", "0.76", "-0.45", "-0.99", null, "-0.46", "0.28", "0.31", "0.32", "0.42", "-0.00", "0.66", "0.24", "0.31", "0.10", "0.73", "0.02", "0.78", "0.07", "1.00", "0.43", "0.61", "0.53", "0.53", "0.41", "0.37", "0.97", "-0.19"],
|
||||
["AEDGBP", "0.70", "0.73", "0.34", "0.97", "0.84", "0.05", "0.21", "0.14", "0.45", "0.69", "0.41", "-0.53", "0.28", "0.13", "0.99", "0.97", "0.93", "0.62", "0.35", null, "0.18", "0.96", "0.58", "0.04", "0.00", "0.58", "-0.54", "0.35", "0.84", "0.83", "-0.20", "0.51", "0.32", "0.01", "0.95", "0.69", "-0.73", "0.36", "0.78", "0.02", "0.22", "0.39"],
|
||||
["AEDEUR", "0.18", "0.84", "-0.89", "0.90", "-0.25", "0.53", "0.71", "0.80", "0.60", "-0.98", "-0.81", "0.57", "0.72", "0.32", "-0.23", "0.98", "0.50", "0.93", "0.56", "0.26", null, "0.61", "0.47", "0.72", "0.58", "0.19", "0.94", "0.21", "0.47", "0.70", "0.67", "0.85", "0.98", "0.15", "0.21", "0.43", "0.03", "0.92", "0.91", "0.35", "0.70", "0.85"],
|
||||
["AEDJPY", "0.88", "0.62", "0.50", "0.27", "0.56", "0.61", "0.06", "-0.02", "0.42", "0.26", "0.23", "0.83", "-0.55", "0.94", "0.01", "0.72", "-0.43", "0.10", "0.01", "-0.20", "0.13", null, "0.70", "0.10", "0.05", "0.43", "-0.14", "-0.64", "0.80", "0.79", "0.57", "0.14", "0.14", "0.04", "-0.96", "0.59", "0.14", "0.51", "0.23", "0.57", "0.94", "0.88"],
|
||||
["AEDCAD", "0.75", "-0.99", "0.82", "-0.87", "0.79", "1.00", "0.21", "0.30", "-0.40", "0.34", "-0.85", "0.41", "0.79", "0.17", "0.58", "-0.24", "0.18", "0.15", "0.18", "0.44", "0.34", "0.90", null, "0.10", "0.34", "0.31", "0.34", "0.79", "-0.05", "0.19", "-0.86", "0.61", "-0.65", "0.23", "0.59", "0.69", "-0.65", "0.89", "0.97", "0.12", "0.63", "-0.24"],
|
||||
["AEDCHF", "0.67", "0.46", "0.92", "0.22", "0.91", "0.67", "0.81", "0.04", "0.29", "0.13", "0.80", "0.95", "0.29", "0.99", "-0.17", "0.58", "0.64", "0.68", "0.41", "0.69", "0.84", "0.01", "0.04", null, "0.07", "0.16", "0.26", "-0.43", "0.08", "0.58", "0.33", "-0.28", "0.03", "-0.08", "0.54", "-0.91", "0.78", "-0.10", "-0.13", "0.15", "0.62", "-0.13"],
|
||||
["JPYUSD", "-0.67", "0.90", "0.84", "0.10", "0.77", "0.43", "0.59", "0.69", "0.63", "0.82", "-0.61", "0.41", "0.07", "0.48", "1.00", "-0.52", "0.22", "0.89", "0.43", "0.54", "0.56", "-0.43", "0.78", "0.67", null, "0.06", "0.28", "0.04", "0.62", "0.18", "0.77", "0.63", "0.05", "0.87", "0.22", "0.21", "0.07", "0.25", "-0.55", "0.67", "0.10", "-0.67"],
|
||||
["JPYGBP", "0.21", "0.46", "0.23", "0.53", "-0.97", "0.78", "0.43", "0.74", "-0.95", "0.98", "0.49", "0.66", "0.18", "0.55", "-0.33", "0.67", "0.65", "0.23", "-0.07", "-0.67", "0.56", "0.74", "-0.38", "-0.83", "-0.51", null, "-0.26", "-0.79", "0.73", "-0.78", "-0.09", "0.19", "0.48", "0.97", "0.11", "0.19", "0.51", "0.32", "0.81", "-0.02", "0.17", "0.48"],
|
||||
["JPYEUR", "0.83", "0.86", "0.62", "-0.92", "0.64", "0.58", "0.55", "0.07", "0.81", "0.32", "0.33", "0.96", "0.48", "0.57", "0.25", "0.56", "0.33", "0.02", "-0.79", "0.44", "0.95", "0.35", "0.41", "0.06", "0.28", "0.77", null, "0.64", "0.79", "0.74", "0.67", "-0.97", "0.47", "-0.11", "0.03", "0.39", "-0.37", "0.06", "0.09", "0.13", "0.20", "0.87"],
|
||||
["JPYAED", "0.69", "0.80", "0.90", "0.06", "0.55", "0.90", "-0.09", "0.05", "-0.10", "0.31", "0.57", "0.69", "-0.78", "0.42", "0.64", "0.96", "0.08", "-0.76", "0.59", "0.00", "0.40", "-0.88", "0.69", "0.17", "-0.16", "0.57", "0.86", null, "-0.61", "-0.14", "0.41", "-0.16", "0.36", "0.95", "0.44", "0.41", "0.35", "-0.56", "0.25", "0.66", "0.90", "0.82"],
|
||||
["JPYCAD", "0.33", "0.27", "0.61", "0.01", "-0.16", "0.21", "0.57", "-0.41", "-0.56", "0.55", "0.13", "-0.87", "0.19", "0.64", "-0.38", "-0.80", "-0.10", "0.44", "0.72", "-0.72", "0.48", "0.42", "0.84", "0.73", "0.35", "0.68", "0.01", "0.09", null, "0.87", "0.17", "0.45", "0.02", "0.01", "0.77", "0.24", "0.62", "0.39", "-0.73", "0.21", "-0.08", "0.42"],
|
||||
["JPYCHF", "-0.45", "0.52", "0.34", "0.85", "0.16", "0.96", "0.53", "0.62", "0.46", "0.94", "0.08", "-0.68", "0.81", "0.44", "0.27", "0.75", "-0.84", "0.69", "-0.99", "0.41", "0.66", "-0.94", "0.21", "0.85", "-0.08", "0.36", "0.62", "0.25", "-0.48", null, "0.51", "-0.39", "0.60", "0.63", "0.68", "0.10", "0.62", "0.68", "0.00", "0.24", "0.61", "0.23"],
|
||||
["CADUSD", "-0.65", "0.73", "0.93", "0.27", "-0.00", "-0.46", "0.53", "0.36", "0.83", "0.58", "0.40", "0.03", "0.32", "0.38", "-0.53", "0.86", "0.42", "0.90", "0.83", "0.94", "0.34", "-0.56", "0.46", "-0.72", "0.13", "0.08", "0.25", "0.59", "0.75", "0.72", null, "0.62", "0.73", "0.52", "0.28", "0.03", "-0.54", "0.50", "0.76", "-0.28", "0.89", "0.97"],
|
||||
["CADGBP", "0.74", "0.58", "0.55", "0.01", "0.33", "0.61", "0.75", "0.86", "-0.87", "0.50", "0.57", "0.84", "-0.34", "1.00", "0.77", "0.75", "0.40", "0.12", "-0.57", "-0.16", "-0.91", "0.06", "0.67", "-0.55", "0.02", "0.78", "0.57", "0.70", "0.21", "0.95", "-0.91", null, "-0.82", "0.71", "0.36", "0.46", "0.46", "0.24", "0.15", "0.54", "0.15", "0.83"],
|
||||
["CADEUR", "-0.58", "0.29", "0.03", "0.70", "0.77", "0.80", "0.52", "0.04", "0.11", "0.86", "-0.98", "0.02", "0.01", "-0.19", "-0.48", "0.80", "0.90", "0.10", "0.28", "0.88", "0.98", "0.43", "0.47", "-0.41", "-0.92", "0.49", "0.64", "-0.60", "0.11", "0.61", "0.19", "-0.39", null, "-0.21", "0.56", "-0.45", "-0.48", "0.51", "0.04", "-0.44", "-0.22", "-0.29"],
|
||||
["CADAED", "0.07", "0.55", "0.99", "-0.41", "0.65", "0.75", "0.97", "0.74", "0.65", "0.37", "-0.04", "0.85", "0.83", "0.25", "0.14", "-0.00", "0.80", "0.78", "-0.42", "0.54", "-0.42", "-0.07", "-0.62", "0.56", "0.89", "0.92", "0.19", "0.64", "0.45", "0.24", "0.97", "0.41", "0.36", null, "-0.54", "-0.85", "-0.68", "0.48", "0.13", "0.61", "0.75", "0.21"],
|
||||
["CADJPY", "-0.84", "0.71", "0.59", "-0.78", "0.92", "0.93", "0.03", "0.27", "0.22", "0.71", "-0.79", "0.72", "0.27", "0.29", "0.40", "0.66", "0.44", "-0.33", "0.24", "0.99", "-0.95", "0.74", "0.42", "0.45", "0.08", "0.46", "0.22", "0.70", "0.80", "0.36", "0.36", "0.94", "0.75", "0.51", null, "0.10", "0.31", "0.54", "1.00", "0.78", "0.17", "0.32"],
|
||||
["CADCHF", "0.19", "0.00", "0.62", "-0.63", "0.75", "0.57", "0.28", "-0.98", "0.17", "-0.63", "0.09", "0.10", "-0.09", "0.22", "0.65", "0.20", "0.27", "-0.66", "-0.70", "0.72", "0.40", "0.96", "0.52", "0.38", "0.96", "0.90", "0.35", "-0.70", "0.37", "0.94", "0.20", "0.78", "0.34", "0.24", "-0.18", null, "0.05", "0.71", "0.05", "0.38", "0.02", "0.60"],
|
||||
["CHFUSD", "0.42", "0.61", "-0.30", "-0.27", "0.46", "0.63", "0.64", "0.33", "0.18", "0.88", "0.99", "0.73", "0.85", "0.07", "0.53", "0.31", "-0.63", "0.56", "-0.04", "-0.68", "0.43", "-0.96", "0.45", "0.45", "0.50", "0.17", "0.82", "0.34", "0.26", "0.16", "0.71", "0.35", "0.57", "0.79", "0.56", "0.55", null, "0.02", "-0.90", "0.84", "0.33", "0.18"],
|
||||
["CHFGBP", "-0.38", "0.73", "0.25", "0.64", "0.41", "-0.48", "0.75", "-0.40", "0.37", "0.62", "0.30", "0.06", "0.54", "0.15", "0.51", "0.33", "-0.79", "-0.05", "-0.54", "0.21", "0.40", "0.86", "0.96", "0.94", "0.52", "0.07", "0.71", "-0.80", "-0.40", "0.71", "0.71", "0.89", "0.43", "-0.68", "0.93", "0.05", "0.42", null, "0.59", "-0.67", "0.03", "0.17"],
|
||||
["CHFEUR", "-0.64", "0.96", "-0.34", "0.71", "0.53", "0.44", "0.27", "0.56", "0.96", "0.40", "0.86", "0.65", "0.82", "0.89", "-0.75", "0.29", "0.06", "0.70", "0.23", "0.68", "0.79", "0.21", "0.50", "0.14", "-0.27", "-0.83", "-0.22", "0.59", "0.40", "0.10", "0.88", "0.99", "0.21", "-0.36", "0.00", "0.53", "0.08", "0.08", null, "0.53", "-0.51", "0.03"],
|
||||
["CHFAED", "-0.99", "0.71", "0.51", "0.58", "0.57", "0.73", "0.60", "0.23", "0.02", "0.84", "0.90", "0.56", "0.03", "-0.93", "0.59", "0.24", "-0.67", "0.13", "0.99", "0.28", "0.72", "0.79", "-0.83", "-0.30", "0.73", "0.08", "-0.02", "0.85", "0.33", "0.57", "0.09", "0.26", "0.16", "0.80", "0.65", "-0.19", "-0.38", "-0.61", "-0.98", null, "0.57", "-0.81"],
|
||||
["CHFJPY", "0.60", "0.96", "0.22", "0.52", "0.63", "0.24", "0.76", "0.91", "0.80", "-0.14", "0.59", "-0.01", "0.60", "-0.08", "0.63", "0.39", "0.30", "-0.71", "0.18", "0.94", "-0.30", "0.28", "0.87", "0.92", "-0.19", "0.18", "-0.40", "0.44", "0.88", "0.52", "0.50", "0.44", "0.84", "0.24", "0.09", "0.15", "0.10", "0.30", "-0.05", "0.79", null, "0.99"],
|
||||
["CHFCAD", "0.93", "0.24", "0.05", "0.40", "0.75", "0.12", "0.90", "0.56", "0.46", "0.62", "0.71", "0.01", "0.04", "0.02", "0.49", "0.51", "-0.94", "0.93", "0.80", "-0.40", "0.79", "0.82", "-0.04", "0.38", "-0.24", "-0.17", "0.78", "-0.42", "0.92", "-0.83", "-0.01", "0.54", "0.73", "0.52", "0.95", "0.44", "0.90", "0.81", "0.42", "0.26", "0.36", null]
|
||||
];
|
||||
8
src-trader-dashboard/services/StoreService.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import {createStore} from "redux";
|
||||
|
||||
import fxData from "../reducers/fxDataReducer.jsx";
|
||||
|
||||
class StoreService {
|
||||
}
|
||||
StoreService.STORE = createStore(fxData);
|
||||
export default StoreService;
|
||||
99
src/App.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import "url-search-params-polyfill";
|
||||
|
||||
import DynamicComponentsExample from "./dynamicComponentExample/DynamicComponentsExample";
|
||||
import RichGridExample from "./richGridExample/RichGridExample";
|
||||
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
|
||||
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
|
||||
import FloatingRowComponentExample from "./floatingRowExample/FloatingRowComponentExample";
|
||||
import FullWidthComponentExample from "./fullWidthExample/FullWidthComponentExample";
|
||||
import GroupedRowInnerRendererComponentExample from "./groupedRowInnerRendererExample/GroupedRowInnerRendererComponentExample";
|
||||
import FilterComponentExample from "./filterComponentExample/FilterComponentExample";
|
||||
import MasterDetailExample from "./masterDetailExample/MasterDetailExample";
|
||||
import SimpleReduxExample from "./simpleReduxExample/SimpleReduxExample";
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let searchParams = new URLSearchParams(window.location.search);
|
||||
let fromDocs = searchParams.has("fromDocs");
|
||||
let example = searchParams.has("example") ? searchParams.get("example") : 'rich-grid';
|
||||
|
||||
this.state = {
|
||||
example,
|
||||
fromDocs
|
||||
};
|
||||
|
||||
this.setExample = this.setExample.bind(this);
|
||||
}
|
||||
|
||||
setExample(example) {
|
||||
console.log(example);
|
||||
this.setState({
|
||||
example
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let header = null;
|
||||
if (!this.state.fromDocs) {
|
||||
header = (
|
||||
<ul className="nav nav-pills">
|
||||
<li role="presentation" className={this.state.example === 'rich-grid' ? 'active' : null} onClick={() => this.setExample("rich-grid")}><a href="#">Rich Grid Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'dynamic' ? 'active' : null} onClick={() => this.setExample("dynamic")}><a href="#">Dynamic React Component Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'rich-dynamic' ? 'active' : null} onClick={() => this.setExample("rich-dynamic")}><a href="#">Dynamic React Components - Richer Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'editor' ? 'active' : null} onClick={() => this.setExample("editor")}><a href="#">Cell Editor Component Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'floating-row' ? 'active' : null} onClick={() => this.setExample("floating-row")}><a href="#">Floating Row Renderer Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'full-width' ? 'active' : null} onClick={() => this.setExample("full-width")}><a href="#">Full Width Renderer Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'group-row' ? 'active' : null} onClick={() => this.setExample("group-row")}><a href="#">Grouped Row Inner Renderer Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'filter' ? 'active' : null} onClick={() => this.setExample("filter")}><a href="#">Filters Component Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'master-detail' ? 'active' : null} onClick={() => this.setExample("master-detail")}><a href="#">Master Detail Example</a></li>
|
||||
<li role="presentation" className={this.state.example === 'simple-redux' ? 'active' : null} onClick={() => this.setExample("simple-redux")}><a href="#">Simple Redux Example</a></li>
|
||||
</ul>)
|
||||
}
|
||||
|
||||
let example = null;
|
||||
switch (this.state.example) {
|
||||
case 'dynamic':
|
||||
example = <DynamicComponentsExample/>;
|
||||
break;
|
||||
case 'rich-dynamic':
|
||||
example = <RichComponentsExample/>;
|
||||
break;
|
||||
case 'editor':
|
||||
example = <EditorComponentsExample/>;
|
||||
break;
|
||||
case 'floating-row':
|
||||
example = <FloatingRowComponentExample/>;
|
||||
break;
|
||||
case 'full-width':
|
||||
example = <FullWidthComponentExample/>;
|
||||
break;
|
||||
case 'group-row':
|
||||
example = <GroupedRowInnerRendererComponentExample/>;
|
||||
break;
|
||||
case 'filter':
|
||||
example = <FilterComponentExample/>;
|
||||
break;
|
||||
case 'master-detail':
|
||||
example = <MasterDetailExample/>;
|
||||
break;
|
||||
case 'simple-redux':
|
||||
example = <SimpleReduxExample/>;
|
||||
break;
|
||||
default:
|
||||
example = <RichGridExample/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{header}
|
||||
{example}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default App
|
||||
19
src/dynamicComponentExample/ChildMessageRenderer.jsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ChildMessageRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.invokeParentMethod = this.invokeParentMethod.bind(this);
|
||||
}
|
||||
|
||||
invokeParentMethod() {
|
||||
this.props.context.componentParent.methodFromParent(`Row: ${this.props.node.rowIndex}, Col: ${this.props.colDef.headerName}`)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span><button style={{height: 20}} onClick={this.invokeParentMethod}>Invoke Parent</button></span>
|
||||
);
|
||||
}
|
||||
};
|
||||
21
src/dynamicComponentExample/CubeRenderer.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CubeRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.valueSquared()
|
||||
};
|
||||
}
|
||||
|
||||
valueSquared() {
|
||||
return this.props.value * this.props.value * this.props.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.state.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
17
src/dynamicComponentExample/CurrencyRenderer.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CurrencyRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
formatValueToCurrency(currency, value) {
|
||||
return `${currency}${value}`
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.formatValueToCurrency('EUR', this.props.value)}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
123
src/dynamicComponentExample/DynamicComponentsExample.jsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import SquareRenderer from "./SquareRenderer";
|
||||
import CubeRenderer from "./CubeRenderer";
|
||||
import ParamsRenderer from "./ParamsRenderer";
|
||||
import CurrencyRenderer from "./CurrencyRenderer";
|
||||
import ChildMessageRenderer from "./ChildMessageRenderer";
|
||||
|
||||
export default class DynamicComponentsExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {
|
||||
context: {
|
||||
componentParent: this
|
||||
}
|
||||
},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
|
||||
columnDefs: this.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.refreshRowData = this.refreshRowData.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onCellValueChanged($event) {
|
||||
this.gridApi.refreshCells([$event.node],["cube"]);
|
||||
}
|
||||
|
||||
methodFromParent(cell) {
|
||||
alert(`Parent Component Method from ${cell}!`);
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{headerName: "Row", field: "row", width: 100},
|
||||
{
|
||||
headerName: "Square",
|
||||
field: "value",
|
||||
cellRendererFramework: SquareRenderer,
|
||||
editable:true,
|
||||
colId: "square",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Cube",
|
||||
field: "value",
|
||||
cellRendererFramework: CubeRenderer,
|
||||
colId: "cube",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Row Params",
|
||||
field: "row",
|
||||
cellRendererFramework: ParamsRenderer,
|
||||
colId: "params",
|
||||
width: 215
|
||||
},
|
||||
{
|
||||
headerName: "Currency",
|
||||
field: "currency",
|
||||
cellRendererFramework: CurrencyRenderer,
|
||||
colId: "params",
|
||||
width: 135
|
||||
},
|
||||
{
|
||||
headerName: "Child/Parent",
|
||||
field: "value",
|
||||
cellRendererFramework: ChildMessageRenderer,
|
||||
colId: "params",
|
||||
width: 120
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
refreshRowData() {
|
||||
let rowData = this.createRowData();
|
||||
this.gridApi.setRowData(rowData);
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
let rowData = [];
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
rowData.push({
|
||||
row: "Row " + i,
|
||||
value: i,
|
||||
currency: 1 + Number(Math.random()).toFixed(2)
|
||||
});
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Dynamic React Component Example</h1>
|
||||
<button onClick={this.refreshRowData}>Refresh Data</button>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
gridOptions={this.state.gridOptions}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
13
src/dynamicComponentExample/ParamsRenderer.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ParamsRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>Field: {this.props.colDef.field}, Value: {this.props.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
21
src/dynamicComponentExample/SquareRenderer.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class SquareRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.valueSquared()
|
||||
};
|
||||
}
|
||||
|
||||
valueSquared() {
|
||||
return this.props.value * this.props.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.state.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
82
src/editorComponentExample/EditorComponentsExample.jsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import MoodRenderer from "./MoodRenderer";
|
||||
import MoodEditor from "./MoodEditor";
|
||||
import NumericEditor from "./NumericEditor";
|
||||
|
||||
export default class EditorComponentsExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{headerName: "Name", field: "name", width: 300},
|
||||
{
|
||||
headerName: "Mood",
|
||||
field: "mood",
|
||||
cellRendererFramework: MoodRenderer,
|
||||
cellEditorFramework: MoodEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
},
|
||||
{
|
||||
headerName: "Numeric",
|
||||
field: "number",
|
||||
cellEditorFramework: NumericEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
return [
|
||||
{name: "Bob", mood: "Happy", number: 10},
|
||||
{name: "Harry", mood: "Sad", number: 3},
|
||||
{name: "Sally", mood: "Happy", number: 20},
|
||||
{name: "Mary", mood: "Sad", number: 5},
|
||||
{name: "John", mood: "Happy", number: 15},
|
||||
{name: "Jack", mood: "Happy", number: 25},
|
||||
{name: "Sue", mood: "Sad", number: 43},
|
||||
{name: "Sean", mood: "Sad", number: 1335},
|
||||
{name: "Niall", mood: "Happy", number: 2},
|
||||
{name: "Alberto", mood: "Happy", number: 123},
|
||||
{name: "Fred", mood: "Sad", number: 532},
|
||||
{name: "Jenny", mood: "Happy", number: 34},
|
||||
{name: "Larry", mood: "Happy", number: 13},
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Cell Editor Component Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
107
src/editorComponentExample/MoodEditor.jsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, {Component} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
export default class MoodEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onHappyClick = this.onHappyClick.bind(this);
|
||||
this.onSadClick = this.onSadClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
happy: false
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setHappy(this.props.value === "Happy");
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
let container = ReactDOM.findDOMNode(this.refs.container);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.state.happy ? "Happy" : "Sad";
|
||||
}
|
||||
|
||||
isPopup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
setHappy(happy) {
|
||||
this.setState({
|
||||
happy
|
||||
});
|
||||
}
|
||||
|
||||
onHappyClick() {
|
||||
this.setState({
|
||||
happy: true
|
||||
},
|
||||
() => this.props.api.stopEditing()
|
||||
);
|
||||
}
|
||||
|
||||
onSadClick() {
|
||||
this.setState({
|
||||
happy: false
|
||||
},
|
||||
() => this.props.api.stopEditing()
|
||||
);
|
||||
}
|
||||
|
||||
toggleMood() {
|
||||
this.setHappy(!this.state.happy);
|
||||
}
|
||||
|
||||
render() {
|
||||
let mood = {
|
||||
borderRadius: 15,
|
||||
border: "1px solid grey",
|
||||
background: "#e6e6e6",
|
||||
padding: 15,
|
||||
textAlign: "center",
|
||||
display: "inline-block",
|
||||
// outline: "none"
|
||||
};
|
||||
|
||||
let unselected = {
|
||||
paddingLleft: 10,
|
||||
paddingRight: 10,
|
||||
border: "1px solid transparent",
|
||||
padding: 4
|
||||
};
|
||||
|
||||
let selected = {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
border: "1px solid lightgreen",
|
||||
padding: 4
|
||||
};
|
||||
|
||||
let happyStyle = this.state.value === 'Happy' ? selected : unselected;
|
||||
let sadStyle = this.state.value !== 'Happy' ? selected : unselected;
|
||||
|
||||
return (
|
||||
<div ref="container"
|
||||
style={mood}>
|
||||
<img src="images/smiley.png" onClick={this.onHappyClick} style={happyStyle}/>
|
||||
<img src="images/smiley-sad.png" onClick={this.onSadClick} style={sadStyle}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
27
src/editorComponentExample/MoodRenderer.jsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class MoodRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setMood(this.props.value)
|
||||
}
|
||||
|
||||
refresh(params) {
|
||||
this.setMood(params.value);
|
||||
}
|
||||
|
||||
setMood(mood) {
|
||||
this.setState({
|
||||
imgForMood: mood === 'Happy' ? 'images/smiley.png' : 'images/smiley-sad.png'
|
||||
})
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<img width="20px" src={this.state.imgForMood}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
83
src/editorComponentExample/NumericEditor.jsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import React, {Component} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
export default class MoodEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.props.value
|
||||
};
|
||||
|
||||
this.cancelBeforeStart = this.props.charPress && ('1234567890'.indexOf(this.props.charPress) < 0);
|
||||
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
let container = ReactDOM.findDOMNode(this.refs.input);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.state.value;
|
||||
}
|
||||
|
||||
isCancelBeforeStart() {
|
||||
return this.cancelBeforeStart;
|
||||
}
|
||||
|
||||
// will reject the number if it greater than 1,000,000
|
||||
// not very practical, but demonstrates the method.
|
||||
isCancelAfterEnd() {
|
||||
return this.state.value > 1000000;
|
||||
};
|
||||
|
||||
onKeyDown(event) {
|
||||
if (!this.isKeyPressedNumeric(event)) {
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
|
||||
getCharCodeFromEvent(event) {
|
||||
event = event || window.event;
|
||||
return (typeof event.which === "undefined") ? event.keyCode : event.which;
|
||||
}
|
||||
|
||||
isCharNumeric(charStr) {
|
||||
return !!/\d/.test(charStr);
|
||||
}
|
||||
|
||||
isKeyPressedNumeric(event) {
|
||||
const charCode = this.getCharCodeFromEvent(event);
|
||||
const charStr = event.key ? event.key : String.fromCharCode(charCode);
|
||||
return this.isCharNumeric(charStr);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input ref="input"
|
||||
value={this.state.value}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
87
src/filterComponentExample/FilterComponentExample.jsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import PartialMatchFilter from "./PartialMatchFilter";
|
||||
|
||||
export default class FilterComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs(),
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.onClicked = this.onClicked.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onClicked() {
|
||||
this.gridApi.getFilterInstance("name").getFrameworkComponentInstance().componentMethod("Hello World!");
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{headerName: "Row", field: "row", width: 400},
|
||||
{
|
||||
headerName: "Filter Component",
|
||||
field: "name",
|
||||
filterFramework: PartialMatchFilter,
|
||||
width: 400
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
return [
|
||||
{"row": "Row 1", "name": "Michael Phelps"},
|
||||
{"row": "Row 2", "name": "Natalie Coughlin"},
|
||||
{"row": "Row 3", "name": "Aleksey Nemov"},
|
||||
{"row": "Row 4", "name": "Alicia Coutts"},
|
||||
{"row": "Row 5", "name": "Missy Franklin"},
|
||||
{"row": "Row 6", "name": "Ryan Lochte"},
|
||||
{"row": "Row 7", "name": "Allison Schmitt"},
|
||||
{"row": "Row 8", "name": "Natalie Coughlin"},
|
||||
{"row": "Row 9", "name": "Ian Thorpe"},
|
||||
{"row": "Row 10", "name": "Bob Mill"},
|
||||
{"row": "Row 11", "name": "Willy Walsh"},
|
||||
{"row": "Row 12", "name": "Sarah McCoy"},
|
||||
{"row": "Row 13", "name": "Jane Jack"},
|
||||
{"row": "Row 14", "name": "Tina Wills"}
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Filter Component Example</h1>
|
||||
<button style={{marginBottom: 10}} onClick={this.onClicked}>Filter Instance Method</button>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
enableFilter
|
||||
suppressMenuColumnPanel // ag-enterprise only
|
||||
suppressMenuMainPanel // ag-enterprise only
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
70
src/filterComponentExample/PartialMatchFilter.jsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import React, {Component} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
export default class PartialMatchFilter extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
text: ''
|
||||
}
|
||||
this.valueGetter = this.props.valueGetter;
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
isFilterActive() {
|
||||
return this.state.text !== null && this.state.text !== undefined && this.state.text !== '';
|
||||
}
|
||||
|
||||
doesFilterPass(params) {
|
||||
return this.state.text.toLowerCase()
|
||||
.split(" ")
|
||||
.every((filterWord) => {
|
||||
return this.valueGetter(params.node).toString().toLowerCase().indexOf(filterWord) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
getModel() {
|
||||
return {value: this.state.text};
|
||||
}
|
||||
|
||||
setModel(model) {
|
||||
this.state.text = model ? model.value : '';
|
||||
}
|
||||
|
||||
afterGuiAttached(params) {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
let container = ReactDOM.findDOMNode(this.refs.input);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
componentMethod(message) {
|
||||
alert(`Alert from PartialMatchFilterComponent ${message}`);
|
||||
}
|
||||
|
||||
onChange(event) {
|
||||
let newValue = event.target.value;
|
||||
if (this.state.text !== newValue) {
|
||||
this.setState({
|
||||
text: newValue
|
||||
}, () => {
|
||||
this.props.filterChangedCallback();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>Filter: <input style={{height: "20px"}} ref="input" value={this.state.text} onChange={this.onChange}/></span>
|
||||
);
|
||||
}
|
||||
};
|
||||
85
src/floatingRowExample/FloatingRowComponentExample.jsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import StyledRenderer from "./StyledRenderer";
|
||||
|
||||
export default class FloatingRowComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs(),
|
||||
|
||||
topFloatingRowData: [{row: "Top Row", number: "Top Number"}],
|
||||
bottomFloatingRowData: [{row: "Bottom Row", number: "Bottom Number"}]
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Row",
|
||||
field: "row",
|
||||
width: 400,
|
||||
floatingCellRendererFramework: StyledRenderer,
|
||||
floatingCellRendererParams: {
|
||||
style: {'fontWeight': 'bold'}
|
||||
}
|
||||
},
|
||||
{
|
||||
headerName: "Number",
|
||||
field: "number",
|
||||
width: 399,
|
||||
floatingCellRendererFramework: StyledRenderer,
|
||||
floatingCellRendererParams: {
|
||||
style: {'fontStyle': 'italic'}
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
let rowData = [];
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
rowData.push({
|
||||
row: "Row " + i,
|
||||
number: Math.round(Math.random() * 100)
|
||||
});
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Floating Row Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
floatingTopRowData={this.state.topFloatingRowData}
|
||||
floatingBottomRowData={this.state.bottomFloatingRowData}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
13
src/floatingRowExample/StyledRenderer.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CurrencyRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span style={this.props.style}>{this.props.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
88
src/fullWidthExample/FullWidthComponentExample.jsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import NameAndAgeRenderer from "./NameAndAgeRenderer";
|
||||
|
||||
export default class FullWidthComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
isFullWidthCell(rowNode) {
|
||||
return (rowNode.id === "0") || (parseInt(rowNode.id) % 2 === 0);
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 400
|
||||
},
|
||||
{
|
||||
headerName: "Age",
|
||||
field: "age",
|
||||
width: 399
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
return [
|
||||
{name: "Bob", age: 10},
|
||||
{name: "Harry", age: 3},
|
||||
{name: "Sally", age: 20},
|
||||
{name: "Mary", age: 5},
|
||||
{name: "John", age: 15},
|
||||
{name: "Bob", age: 10},
|
||||
{name: "Harry", age: 3},
|
||||
{name: "Sally", age: 20},
|
||||
{name: "Mary", age: 5},
|
||||
{name: "John", age: 15},
|
||||
{name: "Jack", age: 25},
|
||||
{name: "Sue", age: 43},
|
||||
{name: "Sean", age: 44},
|
||||
{name: "Niall", age: 2},
|
||||
{name: "Alberto", age: 32},
|
||||
{name: "Fred", age: 53},
|
||||
{name: "Jenny", age: 34},
|
||||
{name: "Larry", age: 13},
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Full Width Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
isFullWidthCell={this.isFullWidthCell}
|
||||
fullWidthCellRendererFramework={NameAndAgeRenderer}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
15
src/fullWidthExample/NameAndAgeRenderer.jsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class NameAndAgeRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.values = `Name: ${this.props.data.name}, Age: ${this.props.data.age}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>Full Width Column! { this.values }</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
.ag-group-value .ag-react-container {
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import MedalRenderer from "./MedalRenderer";
|
||||
|
||||
import "./GroupedRowInnerRendererComponentExample.css";
|
||||
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
export default class GroupedRowInnerRendererComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs(),
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Country",
|
||||
field: "country",
|
||||
width: 100,
|
||||
rowGroupIndex: 0
|
||||
},
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Gold",
|
||||
field: "gold",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
{
|
||||
headerName: "Silver",
|
||||
field: "silver",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
{
|
||||
headerName: "Bronze",
|
||||
field: "bronze",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
return [
|
||||
{country: "United States", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "United States", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "United States", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "United Kingdom", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "United Kingdom", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "United Kingdom", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Jamaica", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Jamaica", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Jamaica", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "South Africa", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "John", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "New Zealand", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "New Zealand", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "New Zealand", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Australia", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Australia", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Australia", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Canada", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Canada", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Canada", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Switzerland", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "John", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Spain", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "Spain", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Spain", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Portugal", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Portugal", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Portugal", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Zimbabwe", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Zimbabwe", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Zimbabwe", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Brazil", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "John", gold: 1, silver: 0, bronze: 1}
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 945}}
|
||||
className="ag-fresh">
|
||||
<h1>Group Row Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
groupUseEntireRow
|
||||
groupRowInnerRendererFramework={MedalRenderer}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
18
src/groupedRowInnerRendererExample/MedalRenderer.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class MedalRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.country = this.props.node.key;
|
||||
this.gold = this.props.data.gold;
|
||||
this.silver = this.props.data.silver;
|
||||
this.bronze = this.props.data.bronze;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.country} Gold: {this.gold}, Silver: {this.silver}, Bronze: {this.bronze}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
BIN
src/images/alberto.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
src/images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/images/fire.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
src/images/flags/ar.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
src/images/flags/br.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
src/images/flags/co.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src/images/flags/de.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src/images/flags/es.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
src/images/flags/fr.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src/images/flags/gb.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
src/images/flags/gr.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
src/images/flags/ie.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
src/images/flags/is.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src/images/flags/it.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src/images/flags/mt.png
Normal file
|
After Width: | Height: | Size: 136 B |
BIN
src/images/flags/no.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src/images/flags/pe.png
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
src/images/flags/pt.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
src/images/flags/se.png
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
src/images/flags/uy.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
src/images/flags/ve.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
src/images/frost.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
src/images/horse.png
Normal file
|
After Width: | Height: | Size: 27 KiB |