blob: 1411f0fbe5ba6fe2a58701df5b593b14d29fbd7e [file] [log] [blame]
/*
*
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
var React = require('react');
var mixin = require('../mixins/ButtonEventListener.js')
//TODO: Many values are hard coded, need to make bullet "smarter"
/**
* A bullet graph component.
* It's props values and a brief description below
*
* vertical: If true, the bar rises and falls vertically
* value: The value displayed
* min: The minimum value expected
* max: The maximum value expected
* bulletColor: The fill color of the value section of the graph
* radius: Radius of graph corners.
* containerMarginX: Container's margin along x-axis
* containerMarginY: Container's margin along y-axis
* width: Width of bullet graph in pixels
* height: Height of bullet graph in pixels
* fontSize: Font size of text in pixels
* textMarginX: margin for text on x-axis
* textMarginY: Margin for text on y-axis
* units: units displayed. Also changes whether a max value is displayed.
**/
module.exports = React.createClass({
displayName: 'Bullet',
mixins:mixin.MIXINS,
propTypes: {
vertical: React.PropTypes.bool,
value: React.PropTypes.number,
min: React.PropTypes.number,
max: React.PropTypes.number,
bulletColor: React.PropTypes.string,
radius: React.PropTypes.number,
containerMarginX: React.PropTypes.number,
containerMarginY: React.PropTypes.number,
bulletMargin: React.PropTypes.number,
width: React.PropTypes.number,
height: React.PropTypes.number,
markerX: React.PropTypes.number,
fontSize: React.PropTypes.number,
textMarginX: React.PropTypes.number,
textMarginY: React.PropTypes.number,
units: React.PropTypes.string
},
getDefaultProps: function() {
return {
vertical: false,
value: 0,
min: 0,
max: 100,
bulletColor: "blue",
radius: 4,
containerMarginX: 0,
containerMarginY: 0,
bulletMargin: 0,
width: 512,
height: 64,
markerX: -100,
fontSize: 16,
textMarginX: 5,
textMarginY: 42,
units:''
}
},
/**
* Defines default state.
* value: The value displayed
*/
getInitialState: function() {
return {
value: this.props.value
}
},
/**
* Called when the props are updated.
* Syncs the state value with the prop value.
* @params nextProps
*/
componentWillReceiveProps: function(nextProps) {
this.setState({value:nextProps.value || this.state.value})
},
/**
* Before the component will mount, the width value is recalculed based on browser.
*/
componentWillMount: function() {
var isIE = false || !!document.documentMode;
var range = this.props.max - this.props.min;
var normalizedValue = (this.state.value - this.props.min) / range;
this.isPercent = (!this.props.units || this.props.units == '')? true:false
if (isIE) {
this.bulletWidth = String(Math.round(100 * normalizedValue)) + "%";
} else {
this.bulletWidth = this.props.width - (2 * this.props.containerMarginX);
}
this.displayValue = (this.isPercent)? String(Math.round(normalizedValue * 100)) + "%" : this.props.value
},
/**
* When the component mounts, this function sets the animation for smooth transition on value change. This only
* happens if the user's browser is not IE.
*/
componentDidMount: function() {
var isIE = false || !!document.documentMode;
var range = this.props.max - this.props.min;
var normalizedValue = (this.state.value - this.props.min) / range;
if (!isIE) {
var transform = "scaleX(" + normalizedValue + ")";
var bullet = React.findDOMNode(this.refs.bulletRef);
bullet.style.transform = transform;
bullet.style["-webkit-transform"] = transform;
}
},
/**
* On update, reaplies transformation and width changes made in componentWillMount and componentDidMount
* @param nextProps
* @param nextState
* @returns {boolean}
*/
shouldComponentUpdate: function(nextProps, nextState) {
if (String(this.state.value) == String(nextState.value)) {
return false;
} else {
var isIE = false || !!document.documentMode;
var range = this.props.max - this.props.min;
var normalizedValue = (nextState.value - this.props.min) / range;
if (isIE) {
this.bulletWidth = String(Math.round(100 * normalizedValue)) + "%";
} else {
this.bulletWidth = this.props.width - (2 * this.props.containerMarginX);
var transform = "scaleX(" + normalizedValue + ")";
var bullet = React.findDOMNode(this.refs.bulletRef);
bullet.style.transform = transform;
bullet.style["-webkit-transform"] = transform;
}
this.displayValue = (this.isPercent)? String(Math.round(normalizedValue * 100)) + "%" : nextState.value
return true;
}
},
/**
* Renders the Bullet Component
* @returns {*}
*/
render: function() {
// The text element that displays the difference between the max value and the current value.
var maxDOMEl = (!this.isPercent)? null : React.createElement("text", {
//X needs better logic
// x: this.props.width - this.props.height * 1.25,
x: this.props.width - (130 - this.props.textMarginX),
y: this.props.textMarginY,
fontFamily: "Verdana",
fontSize: this.props.fontSize,
fill: "#ffffff"}, String(this.props.max - this.state.value) + "%");
// The main bullet element. Made up of a static black rect in the background,
// a moving colored rect overlayed on top and a text element for the current value.
var bulletDOM = React.createElement("svg", {
width: "100%",
height: "100%",
viewBox: "0 0 512 " + this.props.height,
preserveAspectRatio: "none"},
React.createElement("rect", {className: "bullet-container",
width: this.props.width - (2 * this.props.containerMarginX),
height: this.props.height - (2 * this.props.containerMarginY),
x: this.props.containerMarginX,
y: this.props.containerMarginY,
rx: this.props.radius,
ry: this.props.radius}, null),
React.createElement("svg", {
x: this.props.containerMarginX,
y: this.props.bulletMargin},
React.createElement("rect", {
className: "bullet",
ref:"bulletRef",
fill: this.props.bulletColor,
width: this.bulletWidth,
height: this.props.height - (2 * this.props.bulletMargin),
rx: this.props.radius,
ry: this.props.radius
})
),
React.createElement("line", {className: "bullet-marker",
x1: this.props.markerX,
x2: this.props.markerX,
y1: this.props.markerY1,
y2: this.props.markerY2}),
React.createElement("text", {
x: this.props.textMarginX,
y: this.props.textMarginY,
"fontFamily": "Verdana",
"fontSize": this.props.fontSize,
fill: "#ffffff"}, this.displayValue
),
maxDOMEl
);
return bulletDOM;
}
});