mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-10 07:05:35 +00:00
Merge branch 'alpha' into Issue_754_Imports_need_to_be_more_graceful
This commit is contained in:
28
.github/workflows/autodeploy.yml
vendored
Normal file
28
.github/workflows/autodeploy.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# This is a basic deployment workflow triggered by pushes to the alpha branch.
|
||||||
|
|
||||||
|
name: Auto-Deploy
|
||||||
|
|
||||||
|
# Controls when the action will run. Workflow runs when the alpha branch receives a push event
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- alpha
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
downloadcode:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
rm -Rf ./coriolis
|
||||||
|
rm -Rf ./coriolis-data
|
||||||
|
git clone https://github.com/alex-williams/coriolis.git --single-branch --branch alpha
|
||||||
|
git clone https://github.com/alex-williams/coriolis-data.git --single-branch --branch alpha
|
||||||
|
cd coriolis-data
|
||||||
|
npm install
|
||||||
|
cd ../coriolis
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
sudo -u www-data cp -r ./build/* /var/www/newdisk/coriolis.brighter-applications.co.uk/
|
||||||
@@ -39,13 +39,17 @@ const GRPCAT = {
|
|||||||
'ml': 'lasers',
|
'ml': 'lasers',
|
||||||
'c': 'projectiles',
|
'c': 'projectiles',
|
||||||
'mc': 'projectiles',
|
'mc': 'projectiles',
|
||||||
|
'advmc': 'projectiles',
|
||||||
'axmc': 'experimental',
|
'axmc': 'experimental',
|
||||||
|
'axmce': 'experimental',
|
||||||
|
'ntp': 'experimental',
|
||||||
'fc': 'projectiles',
|
'fc': 'projectiles',
|
||||||
'rfl': 'experimental',
|
'rfl': 'experimental',
|
||||||
'pa': 'projectiles',
|
'pa': 'projectiles',
|
||||||
'rg': 'projectiles',
|
'rg': 'projectiles',
|
||||||
'mr': 'ordnance',
|
'mr': 'ordnance',
|
||||||
'axmr': 'experimental',
|
'axmr': 'experimental',
|
||||||
|
'axmre': 'experimental',
|
||||||
'rcpl': 'experimental',
|
'rcpl': 'experimental',
|
||||||
'dtl': 'experimental',
|
'dtl': 'experimental',
|
||||||
'tbsc': 'experimental',
|
'tbsc': 'experimental',
|
||||||
@@ -104,7 +108,7 @@ const CATEGORIES = {
|
|||||||
|
|
||||||
// Hardpoints
|
// Hardpoints
|
||||||
'lasers': ['pl', 'ul', 'bl'],
|
'lasers': ['pl', 'ul', 'bl'],
|
||||||
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'],
|
||||||
'ordnance': ['mr', 'tp', 'nl'],
|
'ordnance': ['mr', 'tp', 'nl'],
|
||||||
// Utilities
|
// Utilities
|
||||||
'sb': ['sb'],
|
'sb': ['sb'],
|
||||||
@@ -113,7 +117,7 @@ const CATEGORIES = {
|
|||||||
'defence': ['ch', 'po', 'ec'],
|
'defence': ['ch', 'po', 'ec'],
|
||||||
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
||||||
// Experimental
|
// Experimental
|
||||||
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
'experimental': ['axmc', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
||||||
'weapon stabilizers': ['ews'],
|
'weapon stabilizers': ['ews'],
|
||||||
// Guardian
|
// Guardian
|
||||||
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
||||||
|
|||||||
@@ -1,281 +1,281 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
|
|
||||||
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line Chart
|
* Line Chart
|
||||||
*/
|
*/
|
||||||
export default class LineChart extends TranslatedComponent {
|
export default class LineChart extends TranslatedComponent {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
code: '',
|
code: '',
|
||||||
xMin: 0,
|
xMin: 0,
|
||||||
yMin: 0,
|
yMin: 0,
|
||||||
points: 20,
|
points: 20,
|
||||||
colors: ['#ff8c0d'],
|
colors: ['#ff8c0d'],
|
||||||
aspect: 0.5
|
aspect: 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
func: PropTypes.func.isRequired,
|
func: PropTypes.func.isRequired,
|
||||||
xLabel: PropTypes.string.isRequired,
|
xLabel: PropTypes.string.isRequired,
|
||||||
xMin: PropTypes.number,
|
xMin: PropTypes.number,
|
||||||
xMax: PropTypes.number.isRequired,
|
xMax: PropTypes.number.isRequired,
|
||||||
xUnit: PropTypes.string.isRequired,
|
xUnit: PropTypes.string.isRequired,
|
||||||
xMark: PropTypes.number,
|
xMark: PropTypes.number,
|
||||||
yLabel: PropTypes.string.isRequired,
|
yLabel: PropTypes.string.isRequired,
|
||||||
yMin: PropTypes.number,
|
yMin: PropTypes.number,
|
||||||
yMax: PropTypes.number.isRequired,
|
yMax: PropTypes.number.isRequired,
|
||||||
yUnit: PropTypes.string,
|
yUnit: PropTypes.string,
|
||||||
series: PropTypes.array,
|
series: PropTypes.array,
|
||||||
colors: PropTypes.array,
|
colors: PropTypes.array,
|
||||||
points: PropTypes.number,
|
points: PropTypes.number,
|
||||||
aspect: PropTypes.number,
|
aspect: PropTypes.number,
|
||||||
code: PropTypes.string,
|
code: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
this._updateSeries = this._updateSeries.bind(this);
|
this._updateSeries = this._updateSeries.bind(this);
|
||||||
this._tooltip = this._tooltip.bind(this);
|
this._tooltip = this._tooltip.bind(this);
|
||||||
this._showTip = this._showTip.bind(this);
|
this._showTip = this._showTip.bind(this);
|
||||||
this._hideTip = this._hideTip.bind(this);
|
this._hideTip = this._hideTip.bind(this);
|
||||||
this._moveTip = this._moveTip.bind(this);
|
this._moveTip = this._moveTip.bind(this);
|
||||||
|
|
||||||
const series = props.series;
|
const series = props.series;
|
||||||
|
|
||||||
let xScale = d3.scaleLinear();
|
let xScale = d3.scaleLinear();
|
||||||
let yScale = d3.scaleLinear();
|
let yScale = d3.scaleLinear();
|
||||||
let xAxisScale = d3.scaleLinear();
|
let xAxisScale = d3.scaleLinear();
|
||||||
|
|
||||||
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
||||||
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
xScale,
|
xScale,
|
||||||
xAxisScale,
|
xAxisScale,
|
||||||
yScale,
|
yScale,
|
||||||
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update tooltip content
|
* Update tooltip content
|
||||||
* @param {number} xPos x coordinate
|
* @param {number} xPos x coordinate
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_tooltip(xPos, width) {
|
_tooltip(xPos, width) {
|
||||||
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
||||||
let { xScale, yScale } = this.state;
|
let { xScale, yScale } = this.state;
|
||||||
let { formats, translate } = this.context.language;
|
let { formats, translate } = this.context.language;
|
||||||
let x0 = xScale.invert(xPos),
|
let x0 = xScale.invert(xPos),
|
||||||
y0 = func(x0),
|
y0 = func(x0),
|
||||||
tips = this.tipContainer,
|
tips = this.tipContainer,
|
||||||
yTotal = 0,
|
yTotal = 0,
|
||||||
flip = (xPos / width > 0.50),
|
flip = (xPos / width > 0.50),
|
||||||
tipWidth = 0,
|
tipWidth = 0,
|
||||||
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
||||||
|
|
||||||
|
|
||||||
xPos = xScale(x0); // Clamp xPos
|
xPos = xScale(x0); // Clamp xPos
|
||||||
|
|
||||||
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
||||||
let yVal = series ? y0[series[i]] : y0;
|
let yVal = series ? y0[series[i]] : y0;
|
||||||
yTotal += yVal;
|
yTotal += yVal;
|
||||||
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
||||||
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
||||||
|
|
||||||
tips.selectAll('text').each(function() {
|
tips.selectAll('text').each(function() {
|
||||||
if (this.getBBox().width > tipWidth) {
|
if (this.getBBox().width > tipWidth) {
|
||||||
tipWidth = Math.ceil(this.getBBox().width);
|
tipWidth = Math.ceil(this.getBBox().width);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
||||||
|
|
||||||
tipWidth += 8;
|
tipWidth += 8;
|
||||||
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
||||||
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
||||||
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
||||||
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
||||||
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions based on properties and scale
|
* Update dimensions based on properties and scale
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {number} scale size ratio / scale
|
* @param {number} scale size ratio / scale
|
||||||
* @param {number} width current width of the container
|
* @param {number} width current width of the container
|
||||||
* @returns {Object} calculated dimensions
|
* @returns {Object} calculated dimensions
|
||||||
*/
|
*/
|
||||||
_updateDimensions(props, scale, width) {
|
_updateDimensions(props, scale, width) {
|
||||||
const { xMax, xMin, yMin, yMax } = props;
|
const { xMax, xMin, yMin, yMax } = props;
|
||||||
const innerWidth = width - MARGIN.left - MARGIN.right;
|
const innerWidth = width - MARGIN.left - MARGIN.right;
|
||||||
const outerHeight = Math.round(width * props.aspect);
|
const outerHeight = Math.round(width * props.aspect);
|
||||||
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
||||||
|
|
||||||
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
||||||
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
||||||
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
||||||
return { innerWidth, outerHeight, innerHeight };
|
return { innerWidth, outerHeight, innerHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show tooltip
|
* Show tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_showTip(e) {
|
_showTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', null);
|
this.tipContainer.style('display', null);
|
||||||
this.markersContainer.style('display', null);
|
this.markersContainer.style('display', null);
|
||||||
this._moveTip(e);
|
this._moveTip(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move and update tooltip
|
* Move and update tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_moveTip(e, width) {
|
_moveTip(e, width) {
|
||||||
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||||
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide tooltip
|
* Hide tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_hideTip(e) {
|
_hideTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', 'none');
|
this.tipContainer.style('display', 'none');
|
||||||
this.markersContainer.style('display', 'none');
|
this.markersContainer.style('display', 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update series generated from props
|
* Update series generated from props
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} state React Component state
|
* @param {Object} state React Component state
|
||||||
*/
|
*/
|
||||||
_updateSeries(props, state) {
|
_updateSeries(props, state) {
|
||||||
let { func, xMin, xMax, series, points } = props;
|
let { func, xMin, xMax, series, points } = props;
|
||||||
let delta = (xMax - xMin) / points;
|
let delta = (xMax - xMin) / points;
|
||||||
let seriesData = new Array(points);
|
let seriesData = new Array(points);
|
||||||
|
|
||||||
if (delta) {
|
if (delta) {
|
||||||
seriesData = new Array(points);
|
seriesData = new Array(points);
|
||||||
for (let i = 0, x = xMin; i < points; i++) {
|
for (let i = 0, x = xMin; i < points; i++) {
|
||||||
seriesData[i] = [x, func(x)];
|
seriesData[i] = [x, func(x)];
|
||||||
x += delta;
|
x += delta;
|
||||||
}
|
}
|
||||||
seriesData[points - 1] = [xMax, func(xMax)];
|
seriesData[points - 1] = [xMax, func(xMax)];
|
||||||
} else {
|
} else {
|
||||||
let yVal = func(xMin);
|
let yVal = func(xMin);
|
||||||
seriesData = [[0, yVal], [1, yVal]];
|
seriesData = [[0, yVal], [1, yVal]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const markerElems = [];
|
const markerElems = [];
|
||||||
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
||||||
const seriesLines = [];
|
const seriesLines = [];
|
||||||
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
||||||
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
||||||
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
||||||
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
||||||
markerElems.push(<circle key={i} className='marker' r='4' />);
|
markerElems.push(<circle key={i} className='marker' r='4' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
||||||
|
|
||||||
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions and series data based on props and context.
|
* Update dimensions and series data based on props and context.
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this._updateSeries(this.props, this.state);
|
this._updateSeries(this.props, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state based on property and context changes
|
* Update state based on property and context changes
|
||||||
* @param {Object} nextProps Incoming/Next properties
|
* @param {Object} nextProps Incoming/Next properties
|
||||||
* @param {Object} nextContext Incoming/Next conext
|
* @param {Object} nextContext Incoming/Next conext
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextContext) {
|
componentWillReceiveProps(nextProps, nextContext) {
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
|
|
||||||
if (props.code != nextProps.code) {
|
if (props.code != nextProps.code) {
|
||||||
this._updateSeries(nextProps, this.state);
|
this._updateSeries(nextProps, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the chart
|
* Render the chart
|
||||||
* @return {React.Component} Chart SVG
|
* @return {React.Component} Chart SVG
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width, height }) => {
|
{ ({ width, height }) => {
|
||||||
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
||||||
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
||||||
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
||||||
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
||||||
|
|
||||||
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
||||||
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
||||||
return (
|
return (
|
||||||
<div width={width} height={height}>
|
<div width={width} height={height}>
|
||||||
<svg style={{ width: '100%', height: outerHeight }}>
|
<svg style={{ width: '100%', height: outerHeight }}>
|
||||||
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
||||||
<g>{xmark}</g>
|
<g>{xmark}</g>
|
||||||
<g>{lines}</g>
|
<g>{lines}</g>
|
||||||
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
||||||
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{xLabel}</tspan>
|
<tspan>{xLabel}</tspan>
|
||||||
<tspan className='metric'> ({xUnit})</tspan>
|
<tspan className='metric'> ({xUnit})</tspan>
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
||||||
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{yLabel}</tspan>
|
<tspan>{yLabel}</tspan>
|
||||||
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
||||||
{detailElems}
|
{detailElems}
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
{markerElems}
|
{markerElems}
|
||||||
</g>
|
</g>
|
||||||
<rect
|
<rect
|
||||||
fillOpacity='0'
|
fillOpacity='0'
|
||||||
height={innerHeight}
|
height={innerHeight}
|
||||||
width={innerWidth + 1}
|
width={innerWidth + 1}
|
||||||
onMouseEnter={this._showTip}
|
onMouseEnter={this._showTip}
|
||||||
onTouchStart={this._showTip}
|
onTouchStart={this._showTip}
|
||||||
onMouseLeave={this._hideTip}
|
onMouseLeave={this._hideTip}
|
||||||
onTouchEnd={this._hideTip}
|
onTouchEnd={this._hideTip}
|
||||||
onMouseMove={e => this._moveTip(e, width)}
|
onMouseMove={e => this._moveTip(e, width)}
|
||||||
onTouchMove={e => this._moveTip(e, width)}
|
onTouchMove={e => this._moveTip(e, width)}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pie chart
|
* A pie chart
|
||||||
*/
|
*/
|
||||||
export default class PieChart extends Component {
|
export default class PieChart extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired
|
data : PropTypes.array.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.pie = d3.pie().value((d) => d.value);
|
this.pie = d3.pie().value((d) => d.value);
|
||||||
this.colors = CORIOLIS_COLOURS;
|
this.colors = CORIOLIS_COLOURS;
|
||||||
this.arc = d3.arc();
|
this.arc = d3.arc();
|
||||||
this.arc.innerRadius(0);
|
this.arc.innerRadius(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a slice of the pie chart
|
* Generate a slice of the pie chart
|
||||||
* @param {Object} d the data for this slice
|
* @param {Object} d the data for this slice
|
||||||
* @param {number} i the index of this slice
|
* @param {number} i the index of this slice
|
||||||
* @param {number} width the current width of the parent container
|
* @param {number} width the current width of the parent container
|
||||||
* @returns {Object} the SVG for the slice
|
* @returns {Object} the SVG for the slice
|
||||||
*/
|
*/
|
||||||
sliceGenerator(d, i, width) {
|
sliceGenerator(d, i, width) {
|
||||||
if (!d || d.value == 0) {
|
if (!d || d.value == 0) {
|
||||||
// Ignore 0 values
|
// Ignore 0 values
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = this.props;
|
const { data } = this.props;
|
||||||
|
|
||||||
// Push the labels further out from the centre of the slice
|
// Push the labels further out from the centre of the slice
|
||||||
let [labelX, labelY] = this.arc.centroid(d);
|
let [labelX, labelY] = this.arc.centroid(d);
|
||||||
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
||||||
|
|
||||||
// Put the keys in a line with equal spacing
|
// Put the keys in a line with equal spacing
|
||||||
const nonZeroItems = data.filter(d => d.value != 0).length;
|
const nonZeroItems = data.filter(d => d.value != 0).length;
|
||||||
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
||||||
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
||||||
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g key={`group-${i}`}>
|
<g key={`group-${i}`}>
|
||||||
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
||||||
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
||||||
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the component
|
* Render the component
|
||||||
* @returns {object} Markup
|
* @returns {object} Markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => {
|
{ ({ width }) => {
|
||||||
const pie = this.pie(this.props.data),
|
const pie = this.pie(this.props.data),
|
||||||
translate = `translate(${width / 2}, ${width * 0.4})`;
|
translate = `translate(${width / 2}, ${width * 0.4})`;
|
||||||
|
|
||||||
this.arc.outerRadius(width * 0.4);
|
this.arc.outerRadius(width * 0.4);
|
||||||
return (
|
return (
|
||||||
<div width={width} height={width}>
|
<div width={width} height={width}>
|
||||||
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
||||||
<g transform={translate}>
|
<g transform={translate}>
|
||||||
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,386 +1,386 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const MARGIN_LR = 8; // Left/ Right margin
|
const MARGIN_LR = 8; // Left/ Right margin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Horizontal Slider
|
* Horizontal Slider
|
||||||
*/
|
*/
|
||||||
export default class Slider extends React.Component {
|
export default class Slider extends React.Component {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
axis: false,
|
axis: false,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 1,
|
max: 1,
|
||||||
scale: 1 // SVG render scale
|
scale: 1 // SVG render scale
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axis: PropTypes.bool,
|
axis: PropTypes.bool,
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
min: PropTypes.number,
|
min: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
onResize: PropTypes.func,
|
onResize: PropTypes.func,
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._down = this._down.bind(this);
|
this._down = this._down.bind(this);
|
||||||
this._move = this._move.bind(this);
|
this._move = this._move.bind(this);
|
||||||
this._up = this._up.bind(this);
|
this._up = this._up.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this._keydown = this._keydown.bind(this);
|
this._keydown = this._keydown.bind(this);
|
||||||
this._touchstart = this._touchstart.bind(this);
|
this._touchstart = this._touchstart.bind(this);
|
||||||
this._touchend = this._touchend.bind(this);
|
this._touchend = this._touchend.bind(this);
|
||||||
|
|
||||||
this._updatePercent = this._updatePercent.bind(this);
|
this._updatePercent = this._updatePercent.bind(this);
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
|
|
||||||
this.state = { width: 0 };
|
this.state = { width: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch down handler
|
* On Mouse/Touch down handler
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_down(event) {
|
_down(event) {
|
||||||
let rect = event.currentTarget.getBoundingClientRect();
|
let rect = event.currentTarget.getBoundingClientRect();
|
||||||
this.left = rect.left;
|
this.left = rect.left;
|
||||||
this.width = rect.width;
|
this.width = rect.width;
|
||||||
this._move(event);
|
this._move(event);
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage on move
|
* Update the slider percentage on move
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_move(event) {
|
_move(event) {
|
||||||
if(this.width !== null && this.left != null) {
|
if(this.width !== null && this.left != null) {
|
||||||
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this._updatePercent(clientX - this.left, this.width);
|
this._updatePercent(clientX - this.left, this.width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch up handler
|
* On Mouse/Touch up handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_up(event) {
|
_up(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key up handler for keyboard.
|
* Key up handler for keyboard.
|
||||||
* display the number field then set focus to it
|
* display the number field then set focus to it
|
||||||
* when "Enter" key is pressed
|
* when "Enter" key is pressed
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.sliderInputBox._setDisplay('block');
|
this.sliderInputBox._setDisplay('block');
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key down handler
|
* Key down handler
|
||||||
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
||||||
* @param {Event} event Keyboard even
|
* @param {Event} event Keyboard even
|
||||||
*/
|
*/
|
||||||
_keydown(event) {
|
_keydown(event) {
|
||||||
let newVal = this.props.percent * this.props.max;
|
let newVal = this.props.percent * this.props.max;
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
newVal += 1;
|
newVal += 1;
|
||||||
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
newVal -= 1;
|
newVal -= 1;
|
||||||
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch start handler
|
* Touch start handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchstart(event) {
|
_touchstart(event) {
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch end handler
|
* Touch end handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchend(event) {
|
_touchend(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_enter(event) {
|
_enter(event) {
|
||||||
if(event.buttons !== 1) {
|
if(event.buttons !== 1) {
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage
|
* Update the slider percentage
|
||||||
* @param {number} pos Slider drag position
|
* @param {number} pos Slider drag position
|
||||||
* @param {number} width Slider width
|
* @param {number} width Slider width
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_updatePercent(pos, width) {
|
_updatePercent(pos, width) {
|
||||||
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimenions from rendered DOM
|
* Update dimenions from rendered DOM
|
||||||
*/
|
*/
|
||||||
_updateDimensions() {
|
_updateDimensions() {
|
||||||
this.setState({
|
this.setState({
|
||||||
outerWidth: this.node.getBoundingClientRect().width
|
outerWidth: this.node.getBoundingClientRect().width
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add listeners when about to mount
|
* Add listeners when about to mount
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
if (this.props.onResize) {
|
if (this.props.onResize) {
|
||||||
this.resizeListener = this.props.onResize(this._updateDimensions);
|
this.resizeListener = this.props.onResize(this._updateDimensions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger DOM updates on mount
|
* Trigger DOM updates on mount
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._updateDimensions();
|
this._updateDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove listeners on unmount
|
* Remove listeners on unmount
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.resizeListener) {
|
if (this.resizeListener) {
|
||||||
this.resizeListener.remove();
|
this.resizeListener.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the slider
|
* Render the slider
|
||||||
* @return {React.Component} The slider
|
* @return {React.Component} The slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let outerWidth = this.state.outerWidth;
|
let outerWidth = this.state.outerWidth;
|
||||||
let { axis, axisUnit, min, max, scale } = this.props;
|
let { axis, axisUnit, min, max, scale } = this.props;
|
||||||
let style = {
|
let style = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: axis ? '2.5em' : '1.5em',
|
height: axis ? '2.5em' : '1.5em',
|
||||||
boxSizing: 'border-box'
|
boxSizing: 'border-box'
|
||||||
};
|
};
|
||||||
if (!outerWidth) {
|
if (!outerWidth) {
|
||||||
return <svg style={style} ref={node => this.node = node} />;
|
return <svg style={style} ref={node => this.node = node} />;
|
||||||
}
|
}
|
||||||
let margin = MARGIN_LR * scale;
|
let margin = MARGIN_LR * scale;
|
||||||
let width = outerWidth - (margin * 2);
|
let width = outerWidth - (margin * 2);
|
||||||
let pctPos = width * this.props.percent;
|
let pctPos = width * this.props.percent;
|
||||||
return <div><svg
|
return <div><svg
|
||||||
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
||||||
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
||||||
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
||||||
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
||||||
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
||||||
{axis && <g style={{ fontSize: '.7em' }}>
|
{axis && <g style={{ fontSize: '.7em' }}>
|
||||||
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
||||||
</g>}
|
</g>}
|
||||||
</svg>
|
</svg>
|
||||||
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
percent={this.props.percent}
|
percent={this.props.percent}
|
||||||
axisUnit={this.props.axisUnit}
|
axisUnit={this.props.axisUnit}
|
||||||
scale={this.props.scale}
|
scale={this.props.scale}
|
||||||
max={this.props.max}
|
max={this.props.max}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
||||||
**/
|
**/
|
||||||
class TextInputBox extends React.Component {
|
class TextInputBox extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._handleFocus = this._handleFocus.bind(this);
|
this._handleFocus = this._handleFocus.bind(this);
|
||||||
this._handleBlur = this._handleBlur.bind(this);
|
this._handleBlur = this._handleBlur.bind(this);
|
||||||
this._handleChange = this._handleChange.bind(this);
|
this._handleChange = this._handleChange.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this.state = this._getInitialState();
|
this.state = this._getInitialState();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update input value if slider changes will change props/state
|
* Update input value if slider changes will change props/state
|
||||||
* @param {Object} nextProps React Component properites
|
* @param {Object} nextProps React Component properites
|
||||||
* @param {Object} nextState React Component state values
|
* @param {Object} nextState React Component state values
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextState) {
|
componentWillReceiveProps(nextProps, nextState) {
|
||||||
let nextValue = nextProps.percent * nextProps.max;
|
let nextValue = nextProps.percent * nextProps.max;
|
||||||
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
||||||
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
||||||
this.setState({ inputValue: nextValue });
|
this.setState({ inputValue: nextValue });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update slider textbox visibility/values if changes are made to slider
|
* Update slider textbox visibility/values if changes are made to slider
|
||||||
* @param {Object} prevProps React Component properites
|
* @param {Object} prevProps React Component properites
|
||||||
* @param {Object} prevState React Component state values
|
* @param {Object} prevState React Component state values
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
||||||
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
||||||
}
|
}
|
||||||
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
||||||
// they chose a different module
|
// they chose a different module
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Set initial state for the textbox.
|
* Set initial state for the textbox.
|
||||||
* We may want to rethink this to
|
* We may want to rethink this to
|
||||||
* try and make it a stateless component
|
* try and make it a stateless component
|
||||||
* @returns {object} React state object with initial values set
|
* @returns {object} React state object with initial values set
|
||||||
*/
|
*/
|
||||||
_getInitialState() {
|
_getInitialState() {
|
||||||
return {
|
return {
|
||||||
divStyle: { display:'none' },
|
divStyle: { display:'none' },
|
||||||
inputStyle: { width:'4em' },
|
inputStyle: { width:'4em' },
|
||||||
labelStyle: { marginLeft: '.1em' },
|
labelStyle: { marginLeft: '.1em' },
|
||||||
maxLength:5,
|
maxLength:5,
|
||||||
size:5,
|
size:5,
|
||||||
min:0,
|
min:0,
|
||||||
tabIndex:-1,
|
tabIndex:-1,
|
||||||
type:'number',
|
type:'number',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} val block or none
|
* @param {string} val block or none
|
||||||
*/
|
*/
|
||||||
_setDisplay(val) {
|
_setDisplay(val) {
|
||||||
this.setState({
|
this.setState({
|
||||||
divStyle: { display:val }
|
divStyle: { display:val }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update the input value
|
* Update the input value
|
||||||
* when textbox gets focus
|
* when textbox gets focus
|
||||||
*/
|
*/
|
||||||
_handleFocus() {
|
_handleFocus() {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue:this._getValue()
|
inputValue:this._getValue()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update inputValue when textbox loses focus
|
* Update inputValue when textbox loses focus
|
||||||
*/
|
*/
|
||||||
_handleBlur() {
|
_handleBlur() {
|
||||||
this._setDisplay('none');
|
this._setDisplay('none');
|
||||||
if (this.state.inputValue !== '') {
|
if (this.state.inputValue !== '') {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @returns {number} inputValue Value of the input box
|
* @returns {number} inputValue Value of the input box
|
||||||
*/
|
*/
|
||||||
_getValue() {
|
_getValue() {
|
||||||
return this.state.inputValue;
|
return this.state.inputValue;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update and set limits on input box
|
* Update and set limits on input box
|
||||||
* values depending on what user
|
* values depending on what user
|
||||||
* has selected
|
* has selected
|
||||||
*
|
*
|
||||||
* @param {SyntheticEvent} event ReactJs onChange event
|
* @param {SyntheticEvent} event ReactJs onChange event
|
||||||
*/
|
*/
|
||||||
_handleChange(event) {
|
_handleChange(event) {
|
||||||
if (event.target.value < 0) {
|
if (event.target.value < 0) {
|
||||||
this.setState({ inputValue: 0 });
|
this.setState({ inputValue: 0 });
|
||||||
} else if (event.target.value <= this.props.max) {
|
} else if (event.target.value <= this.props.max) {
|
||||||
this.setState({ inputValue: event.target.value });
|
this.setState({ inputValue: event.target.value });
|
||||||
} else {
|
} else {
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key up handler for input field.
|
* Key up handler for input field.
|
||||||
* If user hits Enter key, blur/close the input field
|
* If user hits Enter key, blur/close the input field
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
this.sliderVal.blur();
|
this.sliderVal.blur();
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @return {React.Component} Text Input component for Slider
|
* @return {React.Component} Text Input component for Slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let { axisUnit, onChange, percent, scale } = this.props;
|
let { axisUnit, onChange, percent, scale } = this.props;
|
||||||
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +1,80 @@
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
const AXIS_COLOUR = '#C06400';
|
const AXIS_COLOUR = '#C06400';
|
||||||
|
|
||||||
const ASPECT = 1;
|
const ASPECT = 1;
|
||||||
|
|
||||||
const merge = function(one, two) {
|
const merge = function(one, two) {
|
||||||
return Object.assign({}, one, two);
|
return Object.assign({}, one, two);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A vertical bar chart
|
* A vertical bar chart
|
||||||
*/
|
*/
|
||||||
export default class VerticalBarChart extends TranslatedComponent {
|
export default class VerticalBarChart extends TranslatedComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired,
|
data : PropTypes.array.isRequired,
|
||||||
yMax : PropTypes.number
|
yMax : PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._termtip = this._termtip.bind(this);
|
this._termtip = this._termtip.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the bar chart
|
* Render the bar chart
|
||||||
* @returns {Object} the markup
|
* @returns {Object} the markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { tooltip, termtip } = this.context;
|
const { tooltip, termtip } = this.context;
|
||||||
|
|
||||||
// Calculate maximum for Y
|
// Calculate maximum for Y
|
||||||
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
||||||
if (dataMax == -Infinity) dataMax = 0;
|
if (dataMax == -Infinity) dataMax = 0;
|
||||||
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
||||||
const localMax = Math.max(dataMax, yMax);
|
const localMax = Math.max(dataMax, yMax);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => (
|
{ ({ width }) => (
|
||||||
<div width='100%'>
|
<div width='100%'>
|
||||||
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
||||||
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
||||||
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
||||||
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
||||||
<LabelList dataKey='value' position='insideTop'/>
|
<LabelList dataKey='value' position='insideTop'/>
|
||||||
</Bar>
|
</Bar>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a term tip
|
* Generate a term tip
|
||||||
* @param {Object} d the data
|
* @param {Object} d the data
|
||||||
* @param {number} i the index
|
* @param {number} i the index
|
||||||
* @param {Object} e the event
|
* @param {Object} e the event
|
||||||
* @returns {Object} termtip markup
|
* @returns {Object} termtip markup
|
||||||
*/
|
*/
|
||||||
_termtip(d, i, e) {
|
_termtip(d, i, e) {
|
||||||
if (this.props.data[i].tooltip) {
|
if (this.props.data[i].tooltip) {
|
||||||
return this.context.termtip(this.props.data[i].tooltip, e);
|
return this.context.termtip(this.props.data[i].tooltip, e);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const formats = {
|
export const formats = {
|
||||||
decimal: ',',
|
decimal: ',',
|
||||||
thousands: '.',
|
thousands: '.',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['', ' €'],
|
currency: ['', ' €'],
|
||||||
dateTime: '%A, der %e. %B %Y, %X',
|
dateTime: '%A, der %e. %B %Y, %X',
|
||||||
date: '%d.%m.%Y',
|
date: '%d.%m.%Y',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['AM', 'PM'], // unused
|
periods: ['AM', 'PM'], // unused
|
||||||
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
||||||
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
||||||
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||||
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './de.json';
|
export { default as terms } from './de.json';
|
||||||
|
|||||||
@@ -112,11 +112,14 @@
|
|||||||
"mc": "Multi-cannon",
|
"mc": "Multi-cannon",
|
||||||
"mh": "Missing Weapon/Utility",
|
"mh": "Missing Weapon/Utility",
|
||||||
"mm": "Missing Module",
|
"mm": "Missing Module",
|
||||||
|
"advmc": "Multi-cannon (Advanced)",
|
||||||
"axmc": "AX Multi-cannon",
|
"axmc": "AX Multi-cannon",
|
||||||
|
"axmce": "AX Multi-cannon (Enhanced)",
|
||||||
"ml": "Mining Laser",
|
"ml": "Mining Laser",
|
||||||
"mlc": "Multi Limpet Controller",
|
"mlc": "Multi Limpet Controller",
|
||||||
"mr": "Missile Rack",
|
"mr": "Missile Rack",
|
||||||
"axmr": "AX Missile Rack",
|
"axmr": "AX Missile Rack",
|
||||||
|
"axmre": "AX Missile Rack (Enhanced)",
|
||||||
"ews": "Experimental Weapon Stabilizer",
|
"ews": "Experimental Weapon Stabilizer",
|
||||||
"mrp": "Module Reinforcement Package",
|
"mrp": "Module Reinforcement Package",
|
||||||
"nl": "Mine Launcher",
|
"nl": "Mine Launcher",
|
||||||
@@ -162,6 +165,7 @@
|
|||||||
"sua": "Supercruise Assist",
|
"sua": "Supercruise Assist",
|
||||||
"t": "thrusters",
|
"t": "thrusters",
|
||||||
"tp": "Torpedo Pylon",
|
"tp": "Torpedo Pylon",
|
||||||
|
"ntp": "Nanite Torpedo Pylon",
|
||||||
"ul": "Burst Laser",
|
"ul": "Burst Laser",
|
||||||
"Send To EDEngineer": "Send To EDEngineer",
|
"Send To EDEngineer": "Send To EDEngineer",
|
||||||
"Send To EDOMH": "Send To EDOMH",
|
"Send To EDOMH": "Send To EDOMH",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const formats = {
|
export const formats = {
|
||||||
decimal: '.',
|
decimal: '.',
|
||||||
thousands: ',',
|
thousands: ',',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['₩', ''],
|
currency: ['₩', ''],
|
||||||
dateTime: '%a %b %e %X %Y',
|
dateTime: '%a %b %e %X %Y',
|
||||||
date: '%Y/%m/%d',
|
date: '%Y/%m/%d',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['오전', '오후'],
|
periods: ['오전', '오후'],
|
||||||
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
|
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
|
||||||
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
|
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
|
||||||
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
|
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
|
||||||
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
|
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './ko.json';
|
export { default as terms } from './ko.json';
|
||||||
|
|||||||
Reference in New Issue
Block a user