| |
| /* |
| * |
| * 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 ReactDOM = require('react-dom'); |
| var MIXINS = require("../mixins/ButtonEventListener.js"); |
| var Gauge = require("../../js/gauge-modified.js"); |
| var GUID = require("utils/guid"); |
| import _ from 'underscore' |
| |
| |
| |
| |
| /** |
| * Gauge Component |
| * It's props values and a brief description below |
| * |
| * min: minimum value expected |
| * max: maximum value expected |
| * width: width of gauge in px |
| * height: height of gauge in px |
| * value: the number displayed on the gauge |
| * resize: should the gauge resize with container |
| * unit: the units displayed on the gauge |
| * valueFormat: An object with an 'int' and 'dec' property. The 'int' is the min number of integer digits displayed |
| * and the 'dec' object is the min number of fractional digits displayed. |
| * |
| * |
| **/ |
| module.exports = React.createClass({ |
| displayName: 'Gauge', |
| mixins:MIXINS, |
| propTypes: { |
| min: React.PropTypes.number, |
| max: React.PropTypes.number, |
| width: React.PropTypes.number, |
| height: React.PropTypes.string, |
| value: React.PropTypes.number, |
| resize: React.PropTypes.bool, |
| isAggregate: React.PropTypes.bool, |
| units: React.PropTypes.string, |
| valueFormat: React.PropTypes.shape({ |
| 'int': React.PropTypes.number, |
| 'dec': React.PropTypes.number |
| }) |
| }, |
| clone: function(obj) { |
| if (null == obj || "object" != typeof obj) return obj; |
| var copy = obj.constructor(); |
| for (var attr in obj) { |
| if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; |
| } |
| return copy; |
| }, |
| |
| /** |
| * Defines default state. |
| * |
| * min: minimum value expected |
| * max: maximum value expected |
| * nSteps: fixed number for now. The number of ticks in the gauge. |
| * width: width of gauge in px |
| * height: height of gauge in px |
| * value: the number displayed on the gauge |
| * resize: should the gauge resize with container |
| * unit: the units displayed on the gauge |
| * valueFormat: An object with an 'int' and 'dec' property. The 'int' is the min number of integer digits displayed |
| * and the 'dec' object is the min number of fractional digits displayed. |
| */ |
| getInitialState: function() { |
| var valueFormatState = null |
| this.gauge = null; |
| this.gaugeID = GUID(); |
| if (!this.props.valueFormat) { |
| if ((this.props.max && this.props.max > 1000) || this.props.value) { |
| valueFormatState = { |
| "int": 1, |
| "dec": 0 |
| }; |
| } else { |
| valueFormatState = { |
| "int": 1, |
| "dec": 2 |
| }; |
| } |
| } else { |
| valueFormatState = this.props.valueFormat; |
| } |
| return { |
| //sizeOfButton: this.props.size || '', //There is no Medium value in CSS, default size is the absence of a value |
| min: this.props.min || 0, |
| max: this.props.max || 0, |
| nSteps: 14, |
| height: this.props.height || 200, |
| width: this.props.width || 200, |
| color: this.props.color || 'hsla(212, 57%, 50%, 1)', |
| value: this.props.value || 0, |
| valueFormat: valueFormatState, |
| isAggregate: this.props.isAggregate || false, |
| units: this.props.units || '', |
| resize:this.props.resize || false |
| |
| } |
| }, |
| |
| |
| /** |
| * Called when props are changed. Syncs props with state. |
| */ |
| componentWillReceiveProps: function(nextProps) { |
| this.setState({ |
| max:nextProps.max || this.state.max, |
| value:nextProps.value || 0, |
| valueFormat:nextProps.valueFormat || this.state.valueFormat |
| }); |
| }, |
| |
| /** |
| * Calls the render on the gauge object once the component first mounts |
| */ |
| componentDidMount: function() { |
| this.canvasRender(this.state); |
| }, |
| |
| /** |
| * If any of the state variables have changed, the component should update. |
| * Note, this is where the render step occures for the gauge object. |
| */ |
| shouldComponentUpdate: function(nextProps, nextState) { |
| var currentStateString = String(this.state.max) + String(this.state.valueFormat.int) + String(this.state.valueFormat.dec) + String(this.state.value); |
| var nextStateString = String(nextState.max) + String(nextState.valueFormat.int) + String(nextState.valueFormat.dec) + String(nextState.value); |
| if (currentStateString == nextStateString) { |
| return false; |
| } |
| this.state.valueFormat = this.determineValueFormat(nextState.value); |
| this.canvasRender(nextState); |
| return true; |
| }, |
| |
| /** |
| * Default value format based on units. |
| */ |
| determineValueFormat: function(value) { |
| if (value > 999 || this.state.units == "%") { |
| return { |
| "int": 1, |
| "dec": 0 |
| } |
| } |
| |
| return { |
| "int": 1, |
| "dec": 2 |
| } |
| }, |
| |
| |
| /** |
| * Render step for the gauge object. Sets some defaults, passes some of the component's state down. |
| */ |
| canvasRender: function(state) { |
| if (state.max == state.min) { |
| state.max = 14; |
| } |
| var range = state.max - state.min; |
| var step = Math.round(range / state.nSteps); |
| var majorTicks = []; |
| for (var i = 0; i <= state.nSteps; i++) { |
| majorTicks.push(state.min + (i * step)); |
| } |
| var redLine = state.min + (range * 0.9); |
| var config = { |
| isAggregate: state.isAggregate, |
| renderTo: ReactDOM.findDOMNode(document.getElementById(this.gaugeID)), |
| width: state.width, |
| height: state.height, |
| glow: false, |
| units: state.units, |
| title: false, |
| minValue: state.min, |
| maxValue: state.max, |
| majorTicks: majorTicks, |
| valueFormat: this.determineValueFormat(self.value), |
| minorTicks: 0, |
| strokeTicks: false, |
| highlights: [], |
| colors: { |
| plate: 'rgba(0,0,0,0)', |
| majorTicks: 'rgba(15, 123, 182, .84)', |
| minorTicks: '#ccc', |
| title: 'rgba(50,50,50,100)', |
| units: 'rgba(50,50,50,100)', |
| numbers: '#fff', |
| needle: { |
| start: 'rgba(255, 255, 255, 1)', |
| end: 'rgba(255, 255, 255, 1)' |
| } |
| } |
| }; |
| |
| var min = config.minValue; |
| var max = config.maxValue; |
| var N = 1000; |
| var increment = (max - min) / N; |
| for (i = 0; i < N; i++) { |
| var temp_color = 'rgb(0, 172, 238)'; |
| if (i > 0.5714 * N && i <= 0.6428 * N) { |
| temp_color = 'rgb(0,157,217)'; |
| } else if (i >= 0.6428 * N && i < 0.7142 * N) { |
| temp_color = 'rgb(0,142,196)'; |
| } else if (i >= 0.7142 * N && i < 0.7857 * N) { |
| temp_color = 'rgb(0,126,175)'; |
| } else if (i >= 0.7857 * N && i < 0.8571 * N) { |
| temp_color = 'rgb(0,122,154)'; |
| } else if (i >= 0.8571 * N && i < 0.9285 * N) { |
| temp_color = 'rgb(0,96,133)'; |
| } else if (i >= 0.9285 * N) { |
| temp_color = 'rgb(0,80,112)'; |
| } |
| config.highlights.push({ |
| from: i * increment, |
| to: increment * (i + 2), |
| color: temp_color |
| }) |
| } |
| var updateSize = _.debounce(function() { |
| config.maxValue = state.max; |
| }, 500); |
| if (state.resize) $(window).resize(updateSize) |
| |
| if (this.gauge) { |
| this.gauge.setValue(Math.ceil(state.value* 100) / 100) |
| this.gauge.updateConfig(config); |
| } else { |
| this.gauge = new Gauge(config); |
| this.gauge.setValue(Math.ceil(state.value* 100) / 100) |
| this.gauge.draw(); |
| } |
| }, |
| |
| /** |
| * Renders the Gauge Component |
| * Returns the canvas element the gauge will be housed in. |
| * @returns {*} |
| */ |
| render: function() { |
| var gaugeDOM = React.createElement("div", null, |
| React.createElement("canvas", |
| {className: "rwgauge", style: |
| {width:'100%','maxWidth':this.state.width + 'px','maxHeight':this.state.width}, |
| id:this.gaugeID |
| } |
| ) |
| ) |
| |
| |
| |
| return gaugeDOM; |
| } |
| }); |