infect-frontend
Version:
infect fronend
127 lines (109 loc) • 4.45 kB
JSX
import React from 'react';
import BacteriumLabel from '../matrixBacterium/bacteriumLabel';
import Resistance from '../matrixResistance/resistance';
import ResistanceDetail from '../matrixResistance/resistanceDetail';
import SubstanceClassLine from '../matrixSubstanceClass/substanceClassLine';
import { observer } from 'mobx-react';
import { observable, computed } from 'mobx';
import debug from 'debug';
const log = debug('infect:MatrixComponent');
//import DevTools from 'mobx-react-devtools';
export default class Matrix extends React.Component {
svg;
constructor() {
super();
}
componentDidMount() {
this._setupResizeListener();
}
/**
* Returns height of the whole matrix
*/
get height() {
if (!this.props.matrix.defaultRadius) return 0;
// Height: All bact labels + ab label + space between ab label and matrix (matrix.space + matrix.radius),
// see bacteriumLabel
return this.bodyHeight;
}
// Use a bound method for ref:
// https://github.com/facebook/react/issues/4533#issuecomment-276783714
_setSVG = (element) => {
log('SVG set to %o', element);
this._svg = element;
this._setDimensions();
}
_setDimensions() {
if (!this._svg) return;
const dimensions = this._svg.getBoundingClientRect();
log('Set dimensions to %o', dimensions);
this.props.matrix.setDimensions(dimensions);
}
_setupResizeListener() {
window.addEventListener('resize', () => this._setDimensions());
}
get mainMatrixTransformation() {
const left = this.props.matrix.bacteriumLabelColumnWidth + this.props.matrix.spaceBetweenGroups;
return `translate(${ left }, 0)`;
}
/**
* Returns height of the matrix' body (circles).
*/
get bodyHeight() {
// Always display matrix in full height (also for invisible bacteria) or animations will be cut off at the bottom
// (height of matrix changes before the bacteria animate)
return (this.props.matrix.defaultRadius * 2 + this.props.matrix.space) * this.props.matrix.sortedBacteria.length;
}
get visibleBacteriaHeight() {
return (this.props.matrix.defaultRadius * 2 + this.props.matrix.space) * this.props.matrix.sortedVisibleBacteria.length;
}
render() {
return(
<div>
{ /*<DevTools /> */ }
{ /* -with-transitions: only show transitions when a filter changes – before (when
setting up the matrix) we don't want imperformant transitions */ }
{ /* Use width=100% attribute to prevent tiny matrix if css is rendered after JS is executed.
Will be overwritten by CSS */ }
<svg ref={ this._setSVG } width="100%"
style={ { height: this.height, top: this.props.matrix.headerHeight } }
className={'resistanceMatrix__body ' + (this.props.selectedFilters.filterChanges > 0 ? '-with-transitions' : '-no-transitions') }>
{ /* Lines for substance classes in body */ }
{ this.props.matrix.defaultRadius &&
<g transform={ this.mainMatrixTransformation }>
{ this.props.matrix.substanceClasses.map((sc) =>
<SubstanceClassLine key={ sc.substanceClass.id } substanceClass={ sc }
matrix={ this.props.matrix } bodyHeight={ this.visibleBacteriaHeight }/>
) }
</g>
}
{ /* Bacteria labels */ }
<g className="resistanceMatrix__bacteriaLabels">
{ this.props.matrix.sortedBacteria.map((bact) =>
// Don't render bacteria that have no resistanceData
//bact.bacterium.hasDataForResistances &&
<BacteriumLabel key={ bact.bacterium.id } bacterium={ bact } matrix={ this.props.matrix }
selectedFilters={ this.props.selectedFilters }/>
) }
</g>
{ /* Resistances */ }
{ /* Only render when radius is ready and after labels were drawn or we will have multiple re-renders */ }
{ this.props.matrix.defaultRadius &&
<g transform={ this.mainMatrixTransformation } className="resistanceMatrix__resistances">
{ /* Resistances */ }
{ this.props.matrix.resistances.map((res) =>
<Resistance key={res.resistance.antibiotic.id + '/' + res.resistance.bacterium.id}
matrix={this.props.matrix} resistance={res}/>
) }
{ /* Resistance detail (hover) */ }
{ this.props.matrix.activeResistance &&
<ResistanceDetail resistance={ this.props.matrix.activeResistance }
defaultRadius={ this.props.matrix.defaultRadius }/>
}
</g>
}
</svg>
</div>
);
}
}