19
// We will be overiding String and Number to included a parseFix Getter method. This will keep our crazy JavaScript math working
20
// This will take a String or Number and output a float with a maxium number of decimal places but remove trailing 0's since js will have problems with that.
21
Number.prototype.__defineGetter__("parseFix", function() { return function(val) { return parseFloat( parseFloat(this).toFixed(val)) } })
22
String.prototype.__defineGetter__("parseFix", function() { return function(val) { return parseFloat(parseFloat(this).toFixed(val)) } })
24
Number.prototype.__defineGetter__("pointTwoOrSevenFive", function() { return this-parseInt(this) <= .50 ? parseInt(this)+.25 : parseInt(this)+.75 })
18
27
var Graph = function (args) {
119
129
// 1 is x position
120
130
dayInfo.push((curr * this.space_average)+this.graph.options.leftPadding)
121
131
// 2 is y position
122
dayInfo.push(Math.round((this.graph.options.height-this.volume_size-graphBottom)-(parseFloat(this.listModel.get(this.past_len-curr).close-this.min_value)*this.value_adjust)))
132
dayInfo.push(Math.round((this.graph.options.height-this.volume_size-graphBottom)-((this.listModel.get(this.past_len-curr).close-this.min_value)*this.value_adjust).parseFix(12)))
125
135
draw: function () {
127
137
if ( ! this.graph.ctx ) return false
129
this.char_pixel_size = this.graph.ctx.measureText('M').width+5 // S very close calculation of the text chartacter height
130
//this.char_pixel_height = this.graph.ctx.measureText('M').width
131
//this.char_pixel_width = this.graph.ctx.measureText('8').width
139
this.digit_pixel_size = this.graph.ctx.measureText('M').width.parseFix(2)+4 // 5 very close calculation of the digit text chartacter width and height
140
this.chartWidth = this.graph.options.width-this.graph.options.leftPadding-this.graph.options.rightPadding
133
141
this.past_len = this.listModel.count-1
134
this.space_average = parseFloat(((this.graph.options.width-(this.graph.options.leftPadding+this.graph.options.rightPadding))/this.past_len).toFixed(3))
142
this.space_average = (this.chartWidth/this.past_len).parseFix(3)
136
144
if ( this.past_len <= 0 ) {
137
145
this.graph.ctx.clearRect(0, 0, this.graph.options.width, this.graph.options.height)
145
153
this.min_value = 10000000 // This is a "this" so it can be used in the getDay member function
147
155
for ( var x = this.past_len; x >= 0; x-- ) {
148
sn.day_volume = parseFloat(this.listModel.get(x).volume)
149
sn.day_close = parseFloat(this.listModel.get(x).close)
156
sn.day_volume = (this.listModel.get(x).volume).parseFix(2)
157
sn.day_close = (this.listModel.get(x).close).parseFix(2)
150
158
if ( sn.day_volume > sn.max_volume ) sn.max_volume = sn.day_volume
151
159
if ( sn.day_close > sn.max_close_high ) sn.max_close_high = sn.day_close // Get the largest trade value
152
160
if ( sn.day_close < sn.max_close_low ) sn.max_close_low = sn.day_close // Get the smallest trade value
154
162
if ( this.graph.options.showDayRange === "yes" ) {
155
sn.day_high = parseFloat(this.listModel.get(x).high)
156
sn.day_low = parseFloat(this.listModel.get(x).low)
163
sn.day_high = (this.listModel.get(x).high).parseFix(2)
164
sn.day_low = (this.listModel.get(x).low).parseFix(2)
157
165
// These are use when the range bars are active to fit the chart into the demensions
158
166
if ( sn.day_low < this.min_value ) this.min_value = sn.day_low // Get the smallest trade range value
159
167
if ( sn.day_high > sn.max_value ) sn.max_value = sn.day_high // Get the largest trade range value
161
sn.price_length = (parseFloat(sn.max_close_low).toFixed(2).length-1) * this.char_pixel_size // This caclulates the length in pixels of the left trade amount text
162
if ( ((this.past_len-x)*this.space_average)+this.graph.options.leftPadding < sn.price_length ) { // This sets the text down from the day range if nessesary
169
if ( ((this.past_len-x)*this.space_average)+this.graph.options.leftPadding < this.graph.ctx.measureText(parseFloat(sn.max_close_low).toFixed(2)).width.toString() ) { // This sets the text down from the day range if nessesary
163
170
if ( this.min_value < sn.max_close_low ) sn.max_close_low_beg = this.min_value // We do not want the range bar to overlap the text
164
171
if ( sn.max_value > sn.max_close_high_beg ) sn.max_close_high_beg = sn.max_value
179
186
else sn.max_close_low_beg = 0
182
this.min_value = parseFloat(this.min_value).toFixed(2)
189
this.min_value = (this.min_value).parseFix(2)
184
for ( var o in sn ) // We wnat all 2 decimal rounded numbers
185
sn[o] = parseFloat(sn[o]).toFixed(2)
191
for ( var o in sn ) // We want all numbers to be ready for math! Yaae
192
sn[o] = (sn[o]).parseFix(2)
187
194
this.volume_size = Math.round(this.graph.options.height * this.volume_bar_size)
188
195
this.volume_adjust = (this.volume_size/sn.max_volume).toFixed(12)
190
var graph_bottom = this.graph.options.bottomPadding+this.char_pixel_size*2
191
this.value_adjust = (this.graph.options.height-this.graph.options.topPadding-this.volume_size-graph_bottom-this.char_pixel_size) / (sn.max_value-this.min_value)
197
var graph_bottom = this.graph.options.bottomPadding+this.digit_pixel_size*2
198
this.value_adjust = (this.graph.options.height-this.graph.options.topPadding-this.volume_size-graph_bottom-this.digit_pixel_size) / (sn.max_value-this.min_value)
193
200
this.graph.ctx.clearRect(0,0,this.graph.options.width, this.graph.options.height)
196
203
sn.day_high = 0 //Re-using this varible here
197
204
sn.day_low = 0 //Re-using this varible here
198
205
sn.day_close = 0//Re-using this varible here
199
var day_open = 0, text_pos = 0, date_text = ""
201
var oneShot = false, dateSpacing, dateTextLength, dateFormat = ''
203
var dateArray = this.listModel.get(this.past_len).date.split('-')
204
if ( parseInt(dateArray[1]) < parseInt(new Date().getMonth()) ) // This will find if the chart goes back from this month and year for text display
207
var dateSpacing = 10, // Approximate spacing (in pixels) between the dates
209
dateSpace = 0, // Do not change this
215
var keepSpace = 0, oldVolume = []
216
var dateArray = this.listModel.get(this.past_len).date.split('-'),
217
slashLen = this.graph.ctx.measureText('/').width,
218
digitLen = this.graph.ctx.measureText('2').width
220
var dateTextLength = digitLen*2
221
if ( parseInt(dateArray[1]) < parseInt(new Date().getMonth()) ) { // This will find if the chart goes back from this month and year for text display
205
222
dateFormat = 'month'
206
if ( parseInt(dateArray[0]) < parseInt(new Date().getFullYear()) )
223
dateTextLength = digitLen*4+slashLen
224
// The text looks better when the month format is centered
225
dateStart = Math.floor((this.chartWidth+dateSpacing) / (dateTextLength+dateSpacing))
226
dateStart = Math.round((this.chartWidth+dateSpacing - dateStart*(dateTextLength+dateSpacing)) / 2)
229
if ( parseInt(dateArray[0]) < parseInt(new Date().getFullYear()) ) {
207
230
dateFormat = 'year'
231
dateTextLength = digitLen*6+slashLen*2
232
// The text looks better when the year format is centered
233
dateStart = Math.floor((this.chartWidth+dateSpacing) / (dateTextLength+dateSpacing))
234
dateStart = Math.round((this.chartWidth+dateSpacing - dateStart*(dateTextLength+dateSpacing)) / 2)
209
237
var xv = this.graph.options.leftPadding, ff = false
211
240
this.graph.ctx.beginPath()
212
xv = this.graph.options.leftPadding
241
this.graph.ctx.strokeStyle = this.chartLineColor
213
242
this.graph.ctx.moveTo(xv, this.graph.options.height-this.volume_size-graph_bottom )
215
244
for ( var i = this.past_len; i >= 0; i-- ) {
218
if ( !ff ) ff = (this.graph.options.height-this.volume_size-graph_bottom)-(parseFloat(this.listModel.get(i).close-this.min_value)*this.value_adjust).toFixed(2)
219
ff = (this.graph.options.height-this.volume_size-graph_bottom)-(parseFloat(this.listModel.get(i).close-this.min_value)*this.value_adjust).toFixed(2)
245
if ( !ff ) ff = (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(i).close-this.min_value)*this.value_adjust).parseFix(2)
246
ff = (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(i).close-this.min_value)*this.value_adjust).parseFix(2)
221
248
this.graph.ctx.lineTo(xv, ff )
222
this.graph.ctx.strokeStyle = this.chartLineColor
223
this.graph.ctx.stroke();
224
// ----------------------------
225
249
xv += this.space_average
228
252
this.graph.ctx.lineTo(xv-this.space_average, this.graph.options.height-this.volume_size-graph_bottom )
253
this.graph.ctx.closePath()
230
254
this.graph.ctx.stroke()
255
// ----------------------------
232
258
if ( this.graph.options.showDayRange !== "yes" ) {
233
this.graph.ctx.closePath()
234
259
this.graph.ctx.fillStyle = this.graph.ctx.createLinearGradient(this.graph.options.width-this.graph.options.rightPadding, 0,
235
260
this.graph.options.width-this.graph.options.rightPadding, this.graph.options.height-this.volume_size-graph_bottom).addColorStop(0,"#A1A1A1").addColorStop(1,"#ededed")
236
261
this.graph.ctx.fill()
239
264
xv = this.graph.options.leftPadding
241
266
for ( var i = this.past_len; i >= 0; i-- ) {
242
day_open = parseFloat(this.listModel.get(i).open)
243
sn.day_close = parseFloat(this.listModel.get(i).close)
267
day_open = (this.listModel.get(i).open).parseFix(2)
268
sn.day_close = (this.listModel.get(i).close).parseFix(2)
245
270
// Graph day range
246
271
if ( this.graph.options.showDayRange === "yes" ) {
247
sn.day_low = (this.graph.options.height-this.volume_size-graph_bottom)-(parseFloat(this.listModel.get(i).low-this.min_value)*this.value_adjust).toFixed(2)
248
sn.day_high = (this.graph.options.height-this.volume_size-graph_bottom)-(parseFloat(this.listModel.get(i).high-this.min_value)*this.value_adjust).toFixed(2)
249
this.graph.ctx.beginPath()
272
sn.day_low = (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(i).low-this.min_value)*this.value_adjust).parseFix(2)
273
sn.day_high = (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(i).high-this.min_value)*this.value_adjust).parseFix(2)
250
274
if ( day_open < sn.day_close ) { // Going up (green)
251
275
this.graph.ctx.strokeStyle = "#33512A"
252
276
this.graph.ctx.moveTo(xv, sn.day_low)
261
285
//-----------------------------
263
287
// Graph volume bar
264
this.graph.ctx.beginPath();
265
this.graph.ctx.strokeStyle = "#0C276D" // this.graph.options.volumeLineColor"
266
this.graph.ctx.moveTo(xv, this.graph.options.height-graph_bottom+this.char_pixel_size)
267
this.graph.ctx.lineTo(xv, this.graph.options.height-graph_bottom+this.char_pixel_size- (Math.round(parseFloat(this.listModel.get(i).volume)*this.volume_adjust)))
268
this.graph.ctx.fillStyle = this.graph.options.volumeLineColor
269
this.graph.ctx.stroke();
289
keepSpace += this.space_average
290
oldVolume.push(this.graph.options.height-graph_bottom+this.digit_pixel_size- (Math.round(parseFloat(this.listModel.get(i).volume)*this.volume_adjust)))
292
if ( keepSpace > 2.5 ) {
294
this.graph.ctx.beginPath()
295
this.graph.ctx.strokeStyle = this.graph.options.volumeLineColor
296
this.graph.ctx.moveTo((xv).pointTwoOrSevenFive, this.graph.options.height-graph_bottom+this.digit_pixel_size)
297
this.graph.ctx.lineTo((xv).pointTwoOrSevenFive, (oldVolume.map(function(val, ind, ele){this.aveVolume+=val;return this.aveVolume;},{aveVolume: 0}).pop()/oldVolume.length).parseFix(1))
298
this.graph.ctx.closePath()
299
this.graph.ctx.stroke()
270
304
// ----------------------------
272
306
// Graph bottom date text
273
this.graph.ctx.fillStyle = this.graph.options.dateTextColor
275
dateArray = this.listModel.get(i).date.split('-')
277
date_text = dateArray[2].toString()
280
else if ( dateFormat === 'month' ) {
281
date_text = dateArray[1]+"/"+dateArray[2]
284
else if ( dateFormat === 'year' ) {
285
//date_text = this.listModel.get(i).date.split('-') // I wonder how thorough the gargage collection is in qt?
286
//date_text = date_text[1]+"/"+date_text[2]+"/"+date_text[0].substr(2)
287
date_text = dateArray[1]+"/"+dateArray[2]+"/"+dateArray[0].substr(2)
291
dateTextLength = date_text.length*this.char_pixel_size
292
if ( ( text_pos >= dateTextLength/4 && !oneShot ) || ( text_pos >= dateTextLength/2+dateSpacing && i*this.space_average > dateTextLength/4 ) ) {
307
// Make sure there is enough space left to put text
308
if ( text_pos >= dateTextLength/2+dateSpace+dateStart && i*this.space_average+6 > dateTextLength/2 ) {
309
dateSpace = dateSpacing
310
dateStart = dateTextLength/2
313
dateArray = this.listModel.get(i).date.split('-')
315
date_text = dateArray[2].toString()
316
else if ( dateFormat === 'month' )
317
date_text = dateArray[1]+"/"+dateArray[2]
318
else if ( dateFormat === 'year' )
319
date_text = dateArray[1]+"/"+dateArray[2]+"/"+dateArray[0].substr(2)
321
this.graph.ctx.fillStyle = this.graph.options.dateTextColor
295
322
this.graph.ctx.textBaseline = 'bottom'
296
this.graph.ctx.fillText(date_text, xv-dateTextLength/4, this.graph.options.height)
323
this.graph.ctx.fillText(date_text, xv-dateTextLength/2, this.graph.options.height)
298
325
// ----------------------------
300
327
text_pos += this.space_average
301
328
xv += this.space_average
305
this.graph.ctx.beginPath();
330
this.graph.ctx.beginPath()
306
331
this.graph.ctx.strokeStyle = this.graph.options.tradePointColor
307
332
this.graph.ctx.fillStyle = this.graph.options.tradePointColor
308
333
// The top chart line and trade text (high)
320
345
this.graph.ctx.lineTo(this.graph.options.width-this.graph.options.rightPadding, this.chartLineBottom);
321
346
this.graph.ctx.textBaseline = 'top'
322
347
this.graph.ctx.fillText(sn.max_close_low, this.graph.options.leftPadding, this.chartLineBottom+Math.round(sn.max_close_low_beg*this.value_adjust)+1 )
323
this.graph.ctx.stroke();
348
this.graph.ctx.closePath()
349
this.graph.ctx.stroke()
351
this.graph.ctx.beginPath()
353
this.graph.ctx.strokeStyle = this.graph.ctx.createLinearGradient(this.graph.options.width-this.graph.options.rightPadding, 0,
354
this.graph.options.width-this.graph.options.rightPadding, this.graph.options.height-this.volume_size-graph_bottom).addColorStop(0,"#2e2e2e").addColorStop(1,"#ededed")
355
this.graph.ctx.moveTo(this.graph.options.width-this.graph.options.rightPadding, (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(0).close-this.min_value)*this.value_adjust).parseFix(2))
356
this.graph.ctx.lineTo(this.graph.options.width-this.graph.options.rightPadding, this.chartLineBottom)
359
this.graph.ctx.moveTo(this.graph.options.leftPadding, (this.graph.options.height-this.volume_size-graph_bottom)-((this.listModel.get(this.past_len).close-this.min_value)*this.value_adjust).parseFix(2))
360
this.graph.ctx.lineTo(this.graph.options.leftPadding, this.chartLineBottom)
362
this.graph.ctx.closePath()
363
this.graph.ctx.stroke()