Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / framework / widgets / bullet / bullet.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 var React = require('react');
20 var mixin = require('../mixins/ButtonEventListener.js')
21 //TODO: Many values are hard coded, need to make bullet "smarter"
22 /**
23 * A bullet graph component.
24 * It's props values and a brief description below
25 *
26 * vertical: If true, the bar rises and falls vertically
27 * value: The value displayed
28 * min: The minimum value expected
29 * max: The maximum value expected
30 * bulletColor: The fill color of the value section of the graph
31 * radius: Radius of graph corners.
32 * containerMarginX: Container's margin along x-axis
33 * containerMarginY: Container's margin along y-axis
34 * width: Width of bullet graph in pixels
35 * height: Height of bullet graph in pixels
36 * fontSize: Font size of text in pixels
37 * textMarginX: margin for text on x-axis
38 * textMarginY: Margin for text on y-axis
39 * units: units displayed. Also changes whether a max value is displayed.
40 **/
41 module.exports = React.createClass({
42 displayName: 'Bullet',
43 mixins:mixin.MIXINS,
44 propTypes: {
45 vertical: React.PropTypes.bool,
46 value: React.PropTypes.number,
47 min: React.PropTypes.number,
48 max: React.PropTypes.number,
49 bulletColor: React.PropTypes.string,
50 radius: React.PropTypes.number,
51 containerMarginX: React.PropTypes.number,
52 containerMarginY: React.PropTypes.number,
53 bulletMargin: React.PropTypes.number,
54 width: React.PropTypes.number,
55 height: React.PropTypes.number,
56 markerX: React.PropTypes.number,
57 fontSize: React.PropTypes.number,
58 textMarginX: React.PropTypes.number,
59 textMarginY: React.PropTypes.number,
60 units: React.PropTypes.string
61 },
62
63 getDefaultProps: function() {
64 return {
65 vertical: false,
66 value: 0,
67 min: 0,
68 max: 100,
69 bulletColor: "blue",
70 radius: 4,
71 containerMarginX: 0,
72 containerMarginY: 0,
73 bulletMargin: 0,
74 width: 512,
75 height: 64,
76 markerX: -100,
77 fontSize: 16,
78 textMarginX: 5,
79 textMarginY: 42,
80 units:''
81 }
82 },
83
84 /**
85 * Defines default state.
86 * value: The value displayed
87 */
88 getInitialState: function() {
89 return {
90 value: this.props.value
91 }
92 },
93
94 /**
95 * Called when the props are updated.
96 * Syncs the state value with the prop value.
97 * @params nextProps
98 */
99 componentWillReceiveProps: function(nextProps) {
100 this.setState({value:nextProps.value || this.state.value})
101 },
102
103 /**
104 * Before the component will mount, the width value is recalculed based on browser.
105 */
106 componentWillMount: function() {
107 var isIE = false || !!document.documentMode;
108 var range = this.props.max - this.props.min;
109 var normalizedValue = (this.state.value - this.props.min) / range;
110 this.isPercent = (!this.props.units || this.props.units == '')? true:false
111 if (isIE) {
112 this.bulletWidth = String(Math.round(100 * normalizedValue)) + "%";
113 } else {
114 this.bulletWidth = this.props.width - (2 * this.props.containerMarginX);
115 }
116 this.displayValue = (this.isPercent)? String(Math.round(normalizedValue * 100)) + "%" : this.props.value
117
118 },
119
120 /**
121 * When the component mounts, this function sets the animation for smooth transition on value change. This only
122 * happens if the user's browser is not IE.
123 */
124 componentDidMount: function() {
125 var isIE = false || !!document.documentMode;
126 var range = this.props.max - this.props.min;
127 var normalizedValue = (this.state.value - this.props.min) / range;
128 if (!isIE) {
129 var transform = "scaleX(" + normalizedValue + ")";
130 var bullet = React.findDOMNode(this.refs.bulletRef);
131 bullet.style.transform = transform;
132 bullet.style["-webkit-transform"] = transform;
133 }
134 },
135
136 /**
137 * On update, reaplies transformation and width changes made in componentWillMount and componentDidMount
138 * @param nextProps
139 * @param nextState
140 * @returns {boolean}
141 */
142 shouldComponentUpdate: function(nextProps, nextState) {
143
144 if (String(this.state.value) == String(nextState.value)) {
145 return false;
146 } else {
147 var isIE = false || !!document.documentMode;
148 var range = this.props.max - this.props.min;
149 var normalizedValue = (nextState.value - this.props.min) / range;
150
151 if (isIE) {
152 this.bulletWidth = String(Math.round(100 * normalizedValue)) + "%";
153 } else {
154 this.bulletWidth = this.props.width - (2 * this.props.containerMarginX);
155 var transform = "scaleX(" + normalizedValue + ")";
156 var bullet = React.findDOMNode(this.refs.bulletRef);
157 bullet.style.transform = transform;
158 bullet.style["-webkit-transform"] = transform;
159 }
160 this.displayValue = (this.isPercent)? String(Math.round(normalizedValue * 100)) + "%" : nextState.value
161
162 return true;
163 }
164 },
165
166
167
168 /**
169 * Renders the Bullet Component
170 * @returns {*}
171 */
172 render: function() {
173
174 // The text element that displays the difference between the max value and the current value.
175 var maxDOMEl = (!this.isPercent)? null : React.createElement("text", {
176 //X needs better logic
177 // x: this.props.width - this.props.height * 1.25,
178 x: this.props.width - (130 - this.props.textMarginX),
179 y: this.props.textMarginY,
180 fontFamily: "Verdana",
181 fontSize: this.props.fontSize,
182 fill: "#ffffff"}, String(this.props.max - this.state.value) + "%");
183
184
185 // The main bullet element. Made up of a static black rect in the background,
186 // a moving colored rect overlayed on top and a text element for the current value.
187 var bulletDOM = React.createElement("svg", {
188 width: "100%",
189 height: "100%",
190 viewBox: "0 0 512 " + this.props.height,
191 preserveAspectRatio: "none"},
192 React.createElement("rect", {className: "bullet-container",
193 width: this.props.width - (2 * this.props.containerMarginX),
194 height: this.props.height - (2 * this.props.containerMarginY),
195 x: this.props.containerMarginX,
196 y: this.props.containerMarginY,
197 rx: this.props.radius,
198 ry: this.props.radius}, null),
199 React.createElement("svg", {
200 x: this.props.containerMarginX,
201 y: this.props.bulletMargin},
202 React.createElement("rect", {
203 className: "bullet",
204 ref:"bulletRef",
205 fill: this.props.bulletColor,
206 width: this.bulletWidth,
207 height: this.props.height - (2 * this.props.bulletMargin),
208 rx: this.props.radius,
209 ry: this.props.radius
210 })
211 ),
212 React.createElement("line", {className: "bullet-marker",
213 x1: this.props.markerX,
214 x2: this.props.markerX,
215 y1: this.props.markerY1,
216 y2: this.props.markerY2}),
217 React.createElement("text", {
218 x: this.props.textMarginX,
219 y: this.props.textMarginY,
220 "fontFamily": "Verdana",
221 "fontSize": this.props.fontSize,
222 fill: "#ffffff"}, this.displayValue
223 ),
224 maxDOMEl
225 );
226
227
228 return bulletDOM;
229 }
230 });