1class CmcChart { 2 3 debounce(func){ 4 var timer; 5 return function(event){ 6 if(timer) clearTimeout(timer); 7 timer = setTimeout(func,100,event); 8 }; 9 } 10 11 formatCoinCap(val) { 12 if(val == 0) { 13 return '0'; 14 } 15 if(val >= 1000000000000) { 16 return this.currencySymbol + (Math.round(val/10000000000) / 100) + 'T'; 17 } 18 19 if(val >= 100000000) { 20 return this.currencySymbol + (Math.round(val/10000000) / 100) + 'B'; 21 } 22 23 if(val < 0) { 24 if(val <= -1000000000000) { 25 return '-' + this.currencySymbol + Math.abs(Math.round(val/10000000000) / 100) + 'T'; 26 } 27 if(val <= -100000000) { 28 return '- ' + this.currencySymbol + Math.abs(Math.round(val/10000000) / 100) + 'B'; 29 } 30 } 31 32 if(val < 0) { 33 return '-' + this.currencySymbol + Math.abs(Math.round(val/10000) / 100) + 'M'; 34 } 35 36 return this.currencySymbol + (Math.round(val/10000) / 100) + 'M'; 37 } 38 39 loadConfig() { 40 if (typeof this.dateFormat == 'undefined') { 41 this.dateFormat = 'dmy'; 42 } 43 if (typeof this.currencySymbol == 'undefined') { 44 this.currencySymbol = '$'; 45 } 46 this.granularity = 1; 47 this.posX = 0; 48 this.posXMargin = 70; 49 this.posYMargin = 50; 50 this.posXChartMargin = 0; 51 this.height = this.chart.clientHeight - this.posYMargin - 80; 52 this.width = this.chart.clientWidth - this.posXMargin - 5; 53 this.chartMetaData = {}; 54 this.comparisonCursorHasBeenSet = false; 55 56 this.months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; 57 58 if(typeof this.buildChartType != 'undefined') { 59 if(this.buildChartType == "line-chart") { 60 this.buildChartContent = this.buildLineChartContent; 61 } 62 if(this.buildChartType == "bar-chart") { 63 this.buildChartContent = this.buildBarChartContent; 64 if(typeof this.zeroLineClass == 'undefined') { 65 this.zeroLineClass = ''; 66 } 67 68 this.rectWidth = Math.round(((this.width - this.posXMargin) / 2) / this.data.length); 69 if(this.rectWidth < 1) { 70 this.rectWidth = 1; 71 } 72 this.posXChartMargin = this.rectWidth/2; 73 } 74 } else { 75 this.buildChartContent = this.buildLineChartContent; 76 } 77 78 if(typeof this.zeroLineClass == 'undefined') { 79 this.zeroLineClass = 'zero-line'; 80 } 81 } 82 83 /* Build bar chart */ 84 buildBarChartContent() { 85 var rectangles = ""; 86 87 for(var key in this.data) { 88 var entry = this.data[key]; 89 var date; 90 var val; 91 if(typeof entry["d"] == 'undefined') { 92 date = Date.parse(key + "-01-01") / 1000; 93 val = this.data[key]; 94 } else { 95 date = entry["d"]; 96 if(typeof entry["m"] != 'undefined') { 97 val = entry["m"] * 100000; 98 } else if(typeof entry["v"] != 'undefined') { 99 val = entry["v"]; 100 } 101 } 102 103 if(date >= this.dateMin) { 104 this.posX = Math.round(((date - this.dateMin) * (this.width - this.posXChartMargin * 2))/(this.dateMax - this.dateMin)) + this.posXMargin + this.posXChartMargin; 105 } 106 this.posY = this.height - Math.round(((val - this.valMin) * this.height)/(this.valDiff)) + this.posYMargin; 107 108 109 //sparkline = sparkline.concat(this.posX + "," + this.posY); 110 var posYRectStart = this.posY; 111 if(typeof this.zeroLineYpos != 'undefined') { 112 if(this.posY <= this.zeroLineYpos) { 113 var rectHeight = this.zeroLineYpos - this.posY; 114 } else { 115 posYRectStart = this.zeroLineYpos; 116 var rectHeight = this.posY - this.zeroLineYpos; 117 } 118 } else { 119 var rectHeight = (this.posYMargin + this.height) - this.posY; 120 } 121 rectangles = rectangles.concat('<rect class="chart-bar" x="' + (this.posX - this.rectWidth / 2) + '" y="' + posYRectStart + '" width="'+this.rectWidth+'" height="' + rectHeight + '" rx="1" />'); 122 123 this.chartMetaData[this.posX] = {"y":this.posY, "d": date, "m" : val}; 124 val = val / 100000; 125 126 } 127 128 return rectangles; 129 } 130 131 buildLineChartContent() { 132 var isFirstPass = true; 133 var sparklineFill = ""; 134 var sparkline = ""; 135 136 for(var key in this.data) { 137 var entry = this.data[key]; 138 var date; 139 var val; 140 if(typeof entry["d"] == 'undefined') { 141 date = Date.parse(key + "-01-01") / 1000; 142 val = this.data[key]; 143 } else { 144 date = entry["d"]; 145 if(typeof entry["m"] != 'undefined') { 146 val = entry["m"] * 100000; 147 } else if(typeof entry["v"] != 'undefined') { 148 val = entry["v"]; 149 } 150 } 151 152 if(date >= this.dateMin) { 153 this.posX = Math.round(((date - this.dateMin) * this.width)/(this.dateMax - this.dateMin)) + this.posXMargin; 154 } 155 this.posY = this.height - Math.round(((val - this.valMin) * this.height)/(this.valDiff)) + this.posYMargin; 156 157 if(this.posX == 0) { 158 if(isFirstPass) { 159 sparklineFill = 'M' + (this.posXMargin - 2) + ',' + (this.posYMargin + this.height) + ' '; 160 sparkline = "M"; 161 } else { 162 sparkline = "L"; 163 } 164 165 sparkline = sparkline.concat((this.posXMargin - 2) + "," + this.posY); 166 sparklineFill = sparklineFill.concat((this.posXMargin - 2) + "," + this.posY); 167 } else { 168 169 if(isFirstPass) { 170 sparklineFill = 'M' + (this.posXMargin - 2) + ',' + (this.posYMargin + this.height) + ' '; 171 sparkline = "M"; 172 } else { 173 sparkline = sparkline.concat(" L"); 174 sparklineFill = sparklineFill.concat(" L"); 175 } 176 sparkline = sparkline.concat(this.posX + "," + this.posY); 177 sparklineFill = sparklineFill.concat(this.posX + "," + this.posY); 178 } 179 180 this.chartMetaData[this.posX] = {"y":this.posY, "d": date, "m" : val}; 181 val = val / 100000; 182 183 isFirstPass = false;
184 } 185 186 sparklineFill = sparklineFill.concat(' H' + (this.width + this.posXMargin + 2) + ' V' + (this.height + this.posYMargin)); 187 188 return '<path d="' + sparklineFill +'" class="chart-sparkline-fill" stroke-width="0" />' + 189 '<path d="' + sparkline +'" class="chart-sparkline" fill="none" stroke="orange" stroke-width="2px" />'; 190 } 191 192 drawDateLegend() { 193 var dateLegend = ""; 194 195 let difference = this.dateMax - this.dateMin; 196 let totalDays = Math.ceil(difference / (3600 * 24)); 197 console.log('TotalDays: ' + totalDays); 198 199 if(totalDays > 365) { 200 var yearStart = new Date(this.dateMin*1000).getFullYear(); 201 var yearEnd = new Date(this.dateMax*1000).getFullYear(); 202 var numberOfYears = yearEnd - yearStart; 203 204 if(numberOfYears <= 8) { 205 this.granularity = 1; 206 } else if (numberOfYears <= 15) { 207 this.granularity = 3; 208 } else if (numberOfYears <= 20) { 209 this.granularity = 4; 210 } else { 211 this.granularity = 5; 212 } 213 214 for(var i = yearStart; i <= yearEnd; i++) { 215 var timestampYear = Date.parse(i + "-01-01") / 1000; 216 217 var linePosX = Math.round(((timestampYear - this.dateMin) * (this.width - this.posXChartMargin * 2))/(this.dateMax - this.dateMin)) + this.posXMargin; 218 if(linePosX > this.posXMargin && linePosX < this.width + this.posXMargin) { 219 if(i % this.granularity == 0) { 220 dateLegend = dateLegend.concat('<text x="' + linePosX + '" y="' + (this.posYMargin + this.height + 30) + '" text-anchor="middle" class="small">' + i + '</text>'); 221 } 222 } 223 } 224 } else { 225 226 var months = totalDays / 30; 227 if(months <= 6) { 228 this.granularity = 1; 229 } else if (months <= 12) { 230 this.granularity = 3; 231 } else if (months <= 15) { 232 this.granularity = 4; 233 } else { 234 this.granularity = 5; 235 } 236 237 var currentDateTimeStamp = this.dateMin; 238 var i = 0; 239 while(currentDateTimeStamp < this.dateMax && i < 1000) { 240 241 var currentDate = new Date(currentDateTimeStamp*1000); 242 243 var linePosX = Math.round(((currentDateTimeStamp - this.dateMin) * (this.width - this.posXChartMargin * 2))/(this.dateMax - this.dateMin)) + this.posXMargin; 244 245 if(linePosX > this.posXMargin && linePosX < this.width + this.posXMargin) { 246 if(i % this.granularity == 0) { 247 dateLegend = dateLegend.concat('<text x="' + linePosX + '" y="' + (this.posYMargin + this.height + 30) + '" text-anchor="middle" class="small">' + this.months[currentDate.getMonth()] + ' ' + currentDate.getFullYear() + '</text>'); 248 } 249 } 250 251 currentDate.setMonth(currentDate.getMonth() + 1); 252 currentDateTimeStamp = currentDate.getTime() / 1000; 253 i++; 254 } 255 } 256 257 return dateLegend; 258 } 259 260 buildChart() { 261 this.valMax = 0; 262 this.dateMin = undefined; 263 this.dateMax = undefined; 264 this.valMax = undefined; 265 this.valMin = undefined; 266 if(typeof this.setValMin != "undefined") { 267 this.valMin = this.setValMin; 268 } 269 this.loadConfig(); 270 this.loadChartPosition(); 271 272 if (typeof this.data == undefined || this.data.length == 0) { 273 return; 274 } 275 276 for(var key in this.data) { 277 var entry = this.data[key]; 278 var date; 279 var val; 280 if(typeof entry["d"] == 'undefined') { 281 date = Date.parse(key + "-01-01") / 1000; 282 val = this.data[key]; 283 } else { 284 date = entry["d"]; 285 if(typeof entry["m"] != 'undefined') { 286 val = entry["m"] * 100000; 287 } else if(typeof entry["v"] != 'undefined') { 288 val = entry["v"]; 289 } 290 } 291 292 if(val === null) { 293 val = 0; 294 } 295 296 if(typeof this.valMin == "undefined") { 297 this.valMin = parseFloat(val); 298 } else { 299 if(parseFloat(val) < this.valMin) { 300 this.valMin = parseFloat(val); 301 } 302 } 303 304 if(typeof this.valMax == "undefined") { 305 this.valMax = parseFloat(val); 306 } else { 307 if(parseFloat(val) > this.valMax) { 308 this.valMax = parseFloat(val); 309 } 310 } 311 312 if(typeof this.dateMin == "undefined") { 313 this.dateMin = date; 314 } else { 315 if(date < this.dateMin) { 316 this.dateMin = date; 317 } 318 } 319 320 if(typeof this.dateMax == "undefined") { 321 this.dateMax = date; 322 } else { 323 if(date > this.dateMax) { 324 this.dateMax = date; 325 } 326 } 327 } 328 329 // draw date legend 330 var dateLinesForeground = ""; 331 var dateLines = ""; 332 333 dateLines = dateLines.concat(this.drawDateLegend()); 334 335 this.granularity = 0; 336 var i = 1; 337 this.valDiff = this.valMax - this.valMin; 338 339 do { 340 if(this.valDiff <= 6 * i) { 341 this.granularity = 1 * i; 342 } else if (this.valDiff <= 12 * i) { 343 this.granularity = 2 * i; 344 } else if (this.valDiff <= 30 * i) { 345 this.granularity = 5 * i; 346 } 347 348 i = i * 10; 349 } while(this.granularity == 0); 350 this.valMax = this.valMax + this.granularity - (this.valMax % this.granularity); 351 352 this.valDiff = this.valMax - this.valMin; 353 for(i = this.valMin + (this.granularity - (this.valMin % this.granularity)) - this.granularity; i <= this.valMax; i+= this.granularity) { 354 console.log("valMin:" + this.valMin); 355 console.log("i:" + i); 356 this.posY = this.height - Math.round(((i - this.valMin) * this.height)/(this.valDiff)) + this.posYMargin; 357 358 if(this.posY >= this.posYMargin && this.posY <= this.height + this.posYMargin) { 359 if(i == 0) { 360 dateLinesForeground = dateLinesForeground.concat('<line x1="' + this.posXMargin + '" y1="' + this.posY + '" y2="' + this.posY + '" x2="' + (this.posXMargin + this.width) + '" class="chart-line-horizontal ' + this.zeroLineClass +'" />'); 361 dateLinesForeground = dateLinesForeground.concat('<text x="' + (this.posXMargin - 10) + '" y="' + (this.posY + 6) + '" class="small" text-anchor="end">0</text>'); 362 this.zeroLineYpos = this.posY; 363 } else { 364 dateLines = dateLines.concat('<rect x="' + this.posXMargin + '" y="' + this.posY + '" width="' + this.width + '" class="chart-line-horizontal" />'); 365 dateLines = dateLines.concat('<text x="' + (this.posXMargin - 10) + '" y="' + (this.posY + 6) + '" class="small" text-anchor="end">' + this.formatCursorValue(i) + '</text>'); 366 } 367 } 368 } 369 370 var chartContent = this.buildChartContent(); 371 372 //dateLines 373 //sparkline 374 375 var svg = 376 dateLines + 377 378 '<a href="https://companiesmarketcap.com/">' + 379 '<text x="' + Math.round((this.posXMargin + this.width) / 2) + '" y="20" text-anchor="middle" fill="#808080" font-size="20">' + 380 '</text>' + // Title place holder is here 381 '</a>' + 382 chartContent + 383 dateLinesForeground + 384 '<rect x="-100" y="' + this.posYMargin + 'px" width="1px" height="'+ this.height + 'px" class="chart-cursor-line"></rect>' + 385 '<rect x="-100" y="' + this.posYMargin + 'px" width="1px" height="'+ this.height + 'px" class="chart-comparison-cursor-line"></rect>' + 386 387 '<rect x="-150" y="'+this.posYMargin+'" width="100px" height="'+this.height+'" class="chart-comparison-overlay-rect"></rect>' + 388 389 '<circle class="cursorCircleShadow" cx="-50" cy="-50" r="8" opacity="0.5" stroke-width="0" fill="orange" />' + 390 '<circle class="cursor-circle" cx="-50" cy="-50" r="5" stroke-width="1" fill="orange" />' + 391 //'<rect class="cursorTextBox" fill="#ccc">' + 392 '<text font-size="20" class="cursorText" x="0" y="' + (this.posYMargin - 25) + '" text-anchor="middle"></text>' + 393 '<text class="cursorText2" x="0" y="' + (this.posYMargin - 5) + '" text-anchor="middle"></text>' + 394 //'</rect>' + 395 396 '<a href="https://companiesmarketcap.com/">' + 397 '<text x="' + (this.posXMargin + this.width - 220) + '" y="' + (this.posYMargin + this.height + 60) + '" text-anchor="right" fill="#808080">' + 398 'companiesmarketcap.com' + 399 '</text>' +
400 '</a>'; 401 402 this.chart.innerHTML = svg; 403 } 404 405 loadChart(chartElement, chartData) { 406 this.data = chartData; 407 this.chart = chartElement; 408 409 this.loadConfig(); 410 411 this.chart.addEventListener('mousemove', this.updateCursorXY.bind(this)); 412 this.chart.addEventListener('touchstart', this.updateCursorXY.bind(this)); 413 this.chart.addEventListener('touchmove', this.updateCursorXY.bind(this)); 414 this.chart.addEventListener('touchcancel', this.hideChartCursor.bind(this)); 415 this.chart.addEventListener('touchend', this.hideChartCursor.bind(this)); 416 417 if(typeof this.enableComparisonSlider !== "undefined" || this.enableComparisonSlider) { 418 this.chart.addEventListener('pointerdown', this.mousedown.bind(this)); 419 this.chart.addEventListener('pointerup', this.mouseup.bind(this)); 420 } 421 422 if(typeof this.formatCursorValue == "undefined") { 423 this.formatCursorValue = this.formatCoinCap; 424 } 425 if(typeof this.formatCursorDate == "undefined") { 426 this.formatCursorDate = this.formatCursorDateDefault; 427 } 428 429 this.loadChartPosition(); 430 window.addEventListener('scroll', this.loadChartPosition.bind(this)); 431 window.addEventListener('resize', this.buildChart.bind(this)); 432 433 this.buildChart(); 434 } 435 436 loadChartPosition() { 437 this.marketcapchartRect = this.chart.getBoundingClientRect(); 438 439 this.chartXStartMarged = this.posXMargin + this.marketcapchartRect.x - 30; 440 this.chartXEndMarged = this.posXMargin + this.width + this.marketcapchartRect.x + 30; 441 442 this.chartYStartMarged = this.posYMargin + this.marketcapchartRect.y - 5; 443 this.chartYEndMarged = this.posYMargin + this.height + this.marketcapchartRect.y + 5; 444 } 445 446 findNearestKey(needle, target) { 447 var previousK = 0; 448 for (var k in target){ 449 if(Math.abs(k - needle) > Math.abs(previousK - needle)) { 450 return previousK; 451 } 452 previousK = k; 453 } 454 455 return previousK; 456 } 457 458 hideChartCursor() { 459 this.chart.getElementsByClassName('cursorText')[0].setAttribute('x', -150); 460 this.chart.getElementsByClassName('cursorText2')[0].setAttribute('x', -150); 461 this.chart.getElementsByClassName('cursor-circle')[0].setAttribute('cx', -150); 462 this.chart.getElementsByClassName('cursorCircleShadow')[0].setAttribute('cx', -150); 463 this.chart.getElementsByClassName('chart-cursor-line')[0].setAttribute('x', -150); 464 } 465 466 formatCursorDateDefault(date, dateFormat) { 467 if(dateFormat == 'y') { 468 return date.getFullYear(); 469 } else { 470 return date.getDate() + ' ' + this.months[date.getMonth()] + ' ' + date.getFullYear(); 471 } 472 } 473 474 mousedown(event) { 475 if (event.pointerType !== 'mouse') { 476 return; 477 } 478 479 if(true) { // todo check if comparison slider is enabled 480 481 var cursorX = event.clientX; 482 var cursorY = event.clientY; 483 484 console.log(event); 485 486 var nearest = this.findNearestKey((cursorX - this.marketcapchartRect.x), this.chartMetaData); 487 this.chart.getElementsByClassName('chart-comparison-cursor-line')[0].setAttribute('x', nearest); 488 489 490 this.comparisonCursorHasBeenSet = true; 491 this.comparisonNearest = nearest; 492 } 493 } 494 495 mouseup(event) { 496 // hide chart-comparison-cursor-line 497 this.chart.getElementsByClassName('chart-comparison-cursor-line')[0].setAttribute('x', -150); 498 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('x', -150); 499 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('width', 0); 500 this.comparisonCursorHasBeenSet = false; 501 502 this.updateCursorXY(event); 503 } 504 505 updateCursorXY(event) { 506 var cursorX = event.clientX; 507 var cursorY = event.clientY; 508 509 if(typeof cursorX == "undefined" && event.touches[0] != "undefined") { 510 cursorX = event.touches[0].clientX; 511 cursorY = event.touches[0].clientY; 512 } 513 514 console.log("cursor X:" + cursorX); 515 516 if(cursorX > this.chartXStartMarged && cursorX < this.chartXEndMarged && this.chartYStartMarged < cursorY && this.chartYEndMarged > cursorY) { 517 var cursorTextElem = this.chart.getElementsByClassName('cursorText')[0]; 518 var cursorText2Elem = this.chart.getElementsByClassName('cursorText2')[0]; 519 var cursorTextBox = this.chart.getElementsByClassName('cursorTextBox')[0]; 520 var cursorCircle = this.chart.getElementsByClassName('cursor-circle')[0]; 521 var cursorCircleShadow = this.chart.getElementsByClassName('cursorCircleShadow')[0]; 522 523 var nearest = parseFloat(
524 this.findNearestKey((cursorX - this.marketcapchartRect.x), this.chartMetaData) 525 ); 526 527 this.chart.getElementsByClassName('chart-cursor-line')[0].setAttribute('x', nearest); 528 cursorCircle.setAttribute('cx', nearest); 529 cursorCircle.setAttribute('cy', this.chartMetaData[nearest]['y']); 530 cursorCircleShadow.setAttribute('cx', nearest); 531 cursorCircleShadow.setAttribute('cy', this.chartMetaData[nearest]['y']); 532 533 534 535 if(this.comparisonCursorHasBeenSet) { 536 var comparisonPosX = parseInt(this.chart.getElementsByClassName('chart-comparison-cursor-line')[0].getAttribute('x')); 537 if(comparisonPosX > nearest) { 538 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('x', nearest); 539 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('width', 540 Math.abs(nearest - comparisonPosX) 541 ); 542 } else { 543 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('x', comparisonPosX); 544 this.chart.getElementsByClassName('chart-comparison-overlay-rect')[0].setAttribute('width', 545 Math.abs(nearest - comparisonPosX) 546 ); 547 } 548 549 } 550 551 552 553 var date = new Date(this.chartMetaData[nearest]['d'] * 1000); 554 555 if(this.comparisonCursorHasBeenSet) { 556 var comparisonDate = new Date(this.chartMetaData[this.comparisonNearest]['d'] * 1000); 557 558 var percentageClass = "percentage-green"; 559 if((this.comparisonNearest < nearest && this.chartMetaData[this.comparisonNearest]['m'] - this.chartMetaData[nearest]['m'] >= 0) 560 || (this.comparisonNearest > nearest && this.chartMetaData[this.comparisonNearest]['m'] - this.chartMetaData[nearest]['m'] <= 0)) { 561 percentageClass = "percentage-red"; 562 } 563 564 // Calculate the percentage difference 565 566 var val1 = this.chartMetaData[this.comparisonNearest]['m']; 567 var val2 = this.chartMetaData[nearest]['m']; 568 569 if(this.comparisonNearest > nearest) { 570 var val2 = this.chartMetaData[this.comparisonNearest]['m']; 571 var val1 = this.chartMetaData[nearest]['m']; 572 } 573 574 var percentChange = val1 !== 0 ? ((val2 - val1) / Math.abs(val1)) * 100 : 0; 575 var percentChangeText = percentChange >= 0 ? "+" + percentChange.toFixed(2) + "%" : percentChange.toFixed(2) + "%"; 576 577 if(this.comparisonNearest <= nearest) { 578 579 cursorText2Elem.textContent = this.formatCursorDate(comparisonDate, this.dateFormat) + " - " + this.formatCursorDate(date, this.dateFormat); 580 cursorTextElem.innerHTML = this.formatCursorValue(this.chartMetaData[this.comparisonNearest]['m']) + " - " + this.formatCursorValue(this.chartMetaData[nearest]['m']) + " <tspan class=\""+percentageClass+"\">(" + percentChangeText + ")</tspan>"; 581 } else { 582 cursorText2Elem.textContent = this.formatCursorDate(date, this.dateFormat) + " - " + this.formatCursorDate(comparisonDate, this.dateFormat); 583 cursorTextElem.innerHTML = this.formatCursorValue(this.chartMetaData[nearest]['m']) + " - " + this.formatCursorValue(this.chartMetaData[this.comparisonNearest]['m']) + " <tspan class=\""+percentageClass+"\">(" + percentChangeText + ")</tspan>"; 584 } 585 } else { 586 cursorText2Elem.textContent = this.formatCursorDate(date, this.dateFormat); 587 cursorTextElem.textContent = this.formatCursorValue(this.chartMetaData[nearest]['m']); 588 } 589 590 var w1 = (cursorTextElem.getBBox().width/2); 591 var w2 = (cursorText2Elem.getBBox().width/2); 592 593 if(nearest - w1 < this.posXMargin || nearest - w2 < this.posXMargin) { 594 var biggestWidth = (w1 > w2)? w1 : w2; 595 cursorTextElem.setAttribute('x', this.posXMargin + biggestWidth); 596 cursorText2Elem.setAttribute('x', this.posXMargin + biggestWidth); 597 } else if(nearest + w1 > this.posXMargin + this.width || nearest + w2 > this.posXMargin + this.width) { 598 var biggestWidth = (w1 > w2)? w1 : w2; 599 cursorTextElem.setAttribute('x', this.posXMargin + this.width - biggestWidth); 600 cursorText2Elem.setAttribute('x', this.posXMargin + this.width - biggestWidth); 601 } else { 602 cursorTextElem.setAttribute('x', nearest); 603 cursorText2Elem.setAttribute('x', nearest); 604 } 605 } else { 606 this.hideChartCursor(); 607 } 608 } 609 610}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.