1var chart = (function($) { 2 3 4 function chart(canvas, options, chartData, afterRender) { 5 this.canvas = canvas; 6 this.dataSource = chartData; 7 if(!options.templatePath){ 8 options.templatePath = '/sap/sbo/pervasive/IMCC/resources/lib/cvom/resources/chart/templates'; 9 } 10 this.opts = options; 11 this.chartType = chartData.chart_type; 12 this.afterRender = afterRender; 13 } 14 15 chart.prototype.isInCockpit = function(){ 16 try{ 17 return sap.b1.cockpit !== undefined; 18 }catch(e){ 19 return false; 20 } 21 } 22 23 chart.prototype.getChartType = function() { 24 var self = this; 25 if (self.chartType == "Column") { 26 return "info/column"; 27 } else if (self.chartType == "Line" || self.chartType == "Rank") { 28 return "info/line"; 29 } else if (self.chartType == "Area" || self.chartType == "Stacked Area") { 30 return "info/area"; 31 } else if (self.chartType == "Bar" || self.chartType == "Multiple Bar") { 32 return "info/bar"; 33 } else if (self.chartType == "Stacked Column") { 34 return "info/stacked_column" 35 } else if (self.chartType == "Stacked Bar") { 36 return "info/stacked_bar" 37 } else if (self.chartType == "Line-Column") { 38 return "info/combination" 39 } else if (self.chartType == "Pie") { 40 return "info/pie" 41 } else if (self.chartType == "Scatter") { 42 return "info/scatter" 43 } else if (self.chartType == "Bubble") { 44 return "info/bubble" 45 } 46 } 47 48 chart.prototype.hasLegend = function() { 49 var self = this; 50 return self.dataSource.dashboardDetail.legendColors.length > 0; 51 52 } 53 54 chart.prototype.getKey = function(d) { 55 var name = d.metaName; 56 if(d.fieldName){ 57 name = d.fieldName; 58 } 59 60 if (d.opt) { 61 return d.opt + " (" + name + ")"; 62 } 63 return name; 64 } 65 66 chart.prototype.getMeasureKeys = function(index){ 67 var self = this; 68 var measureKeys = self.dataSource.dashboardDetail.measures.list.map(function(d) { 69 return self.getKey(d); 70 }); 71 if(index){ 72 return measureKeys[i] 73 } 74 return measureKeys; 75 } 76 77 chart.prototype.getBinding = function(idx) { 78 var self = this; 79 var dashboard = self.dataSource.dashboardDetail; 80 var measureKeys = self.getMeasureKeys(); 81 var dimKeys = dashboard.dimensions.list.map(function(d) { 82 return self.getKey(d); 83 }); 84 var binding = undefined; 85 86 if (self.chartType == "Pie") { 87 if (idx === undefined) { 88 idx = 0; 89 } 90 binding = [{ 91 "feed": "size", 92 "source": [measureKeys[idx]] 93 }, { 94 "feed": "color", 95 "source": dimKeys 96 }]; 97 98 if (self.dataSource.strategyType == "kmeans") { 99 binding[1].source = ["kmeans"].concat(binding[1].source); 100 } 101 102 if (self.dataSource.strategyType == "abc") { 103 binding[1].source = ["abc"].concat(binding[1].source); 104 } 105 return binding; 106 } 107 108 if (self.chartType == "Scatter" || self.chartType == "Bubble") { 109 binding = [{ 110 "feed": "valueAxis", 111 "source": [measureKeys[0]] 112 }, 113 { 114 "feed": "valueAxis2", 115 "source": [measureKeys[1]] 116 }, 117 { 118 "feed": "color", 119 "source": dimKeys 120 } 121 ]; 122 if (self.chartType == "Bubble") { 123 binding.push({ 124 "feed": "bubbleWidth", 125 "source": [measureKeys[2]] 126 }) 127 } 128 129 130 if (self.dataSource.strategyType == "kmeans") { 131 binding.push({ 132 "feed": "shape", 133 "source": ["kmeans"] 134 }) 135 } 136 137 if (self.dataSource.strategyType == "abc") { 138 binding.push({ 139 "feed": "shape", 140 "source": ["abc"] 141 }) 142 } 143 return binding; 144 } 145 146 var binding = [{ 147 "feed": "valueAxis", 148 "source": measureKeys 149 }, { 150 "feed": "categoryAxis", 151 "source": dimKeys 152 }]; 153 154 if (measureKeys.length > 1) { 155 156 binding.push({ 157 "feed": "color", 158 "source": [{ 159 "measureNames": ["valueAxis"] 160 }] 161 }) 162 } else if (self.hasLegend()) { 163 binding.push({ 164 "feed": "color", 165 "source": dashboard.legendColors.map(function(d) { 166 return d.fieldName; 167 }) 168 }) 169 } 170 171 if (self.dataSource.strategyType == "kmeans") { 172 binding[1].source = ["kmeans"].concat(binding[1].source); 173 } 174 175 if (self.dataSource.strategyType == "abc") { 176 binding[1].source = ["abc"].concat(binding[1].source); 177 } 178 179 return binding; 180 } 181 182 chart.prototype.transformData = function() { 183 var self = this; 184 if (self.dataSource.strategyType == "forecast" && 185 self.dataSource.hasForecastData) { 186 var count = JSON.parse(self.dataSource.strategyParams).m_number; 187 var cols = self.dataSource.cols; 188 for (var i = cols.length - count - 1; i < cols.length; i++) { 189 cols[i][0] = cols[i][0] + " "; 190 } 191 } 192 193 var data = { 194 metadata: { 195 fields: [] 196 }, 197 data: [] 198 }; 199 200 var strategyType = self.dataSource.strategyType; 201 if (strategyType === "kmeans" || strategyType === "abc") { 202 data.metadata.fields.push(self.toMeta(strategyType, "Dimension")) 203 } 204 205 data.metadata.fields = data.metadata.fields.concat( 206 self.dataSource.dashboardDetail.dimensions.list 207 .map(function(d) { 208 return self.toMeta(self.getKey(d), "Dimension"); 209 })) 210 .concat( 211 self.dataSource.dashboardDetail.measures.list 212 .map(function(d) { 213 return self.toMeta(self.getKey(d), "Measure"); 214 })) 215 216 if (self.hasLegend()) { 217 var legendFieldName = self.dataSource.dashboardDetail.legendColors[0].fieldName 218 data.metadata.fields.push(self.toMeta(legendFieldName, "Dimension")); 219 220 data.data = d3.merge(self.dataSource.cols.map(function(col, cIndex) { 221 return self.dataSource.rows.map(function(row) { 222 return col.concat(row.data[cIndex]).concat(row.legendColorValue); 223 }) 224 })) 225 } else { 226 data.data = self.dataSource.cols.map(function(dimension, i) { 227 var result = []; 228 result = result.concat(dimension); 229 self.dataSource.rows.map(function(mesure) { 230 result.push(mesure.data[i]); 231 }) 232 return result; 233 }); 234 } 235 return data; 236 } 237 238 chart.prototype.toMeta = function(key, semanticType) { 239 return { 240 "id": key, 241 "name": key, 242 "semanticType": semanticType, 243 "dataType": semanticType === "Dimension"? "String" :"Number" 244 }; 245 } 246 247 248 chart.prototype.getChartOption = function() { 249 var self = this; 250 var dataSource = self.dataSource; 251 var dimKey = self.getKey(dataSource.dashboardDetail.dimensions.list[0]); 252 253 var getTooltipFormat = function() { 254 var result = {}; 255 dataSource.dashboardDetail.measures.list.map(function(measure, idx) { 256 var key = self.getKey(measure); 257 var valueAccuracy = 2; 258 //TODO below code copy from pre-version 259 //and cannot be verified since no valueType returned ever during my test 260 if (self.isInCockpit()) { 261 var valueType = measure.metaType || measure.type; 262 switch (valueType) { 263 case 'Percent': 264 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.percentAccuracy)) / Math.log(0.1));; 265 break; 266 case 'Measure': 267 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.measureAccuracy)) / Math.log(0.1)); 268 break; 269 case 'Rate': 270 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.rateAccuracy)) / Math.log(0.1)); 271 break; 272 case 'Sum': 273 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.sumAccuracy)) / Math.log(0.1)); 274 break; 275 case 'Queries': 276 case 'FLOAT': 277 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.queryAccuracy)) / Math.log(0.1)); 278 break; 279 case 'Price': 280 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.priceDecimal)) / Math.log(0.1)); 281 break; 282 case 'Quantity': 283 valueAccuracy = Math.round(Math.log(parseFloat(sap.b1.cockpit.utils.CommonUtil.env.decimalAccuracy)) / Math.log(0.1)); 284 break; 285 case 'INTEGER': 286 valueAccuracy = 0; 287 break; 288 }; 289 } 290 291 var pattern = "##,##0.##"; 292 for (var i = 0; i < valueAccuracy; i++) { 293 pattern += "0"; 294 } 295 pattern += "u"; 296 result[key] = pattern; 297 }) 298 return result; 299 } 300 301 var chartOption = { 302 "plotArea": { 303 "dataLabel": { 304 "hideWhenOverlap": true, 305 "visible": !self.opts.isTileMode && self.chartType == "Pie", 306 "formatString": "0.00u" 307 } 308 309 }, 310 "interaction": { 311 "zoom": { 312 "enablement": "enabled" 313 }, 314 "selectability": { 315 "mode": "none" 316 }, 317 hover: { 318 color: "gray" 319 } 320 }, 321 "tooltip": { 322 "formatString": getTooltipFormat(), 323 "postRender": function() { 324 var container = arguments[0][0][0]; 325 $(container).find(".v-body-measure-value").each(function(idx, fragment) { 326 if (!sel.isInCockpit()) { 327 return; 328 } 329 /* 330 * As the locale not set in the cvom, the thousandSeperator and decimalSeperaor 331 * should keep unchanged. (", .") 332 * Also, we used @ here as a temporary flag in case it want's to switch 333 */ 334 var temp = fragment.innerHTML; 335 var origThousandSep = ","; 336 var origDecimalSep = "."; 337 var targetThousandSep = sap.b1.cockpit.utils.CommonUtil.env.thousandSeparator; 338 var targetDecimalSep = sap.b1.cockpit.utils.CommonUtil.env.decimalSeparator; 339 340 341 if (targetThousandSep != origThousandSep) { 342 if (targetThousandSep == origDecimalSep) { 343 targetThousandSep = "@"; 344 } 345 temp = temp.replace("/" + origThousandSep + "/g", targetThousandSep); 346 } 347 348 if (targetDecimalSep != origDecimalSep) { 349 temp = temp.replace(origDecimalSep, targetDecimalSep); 350 } 351 352 if (targetThousandSep == "@") { 353 temp = temp.replace("/@/g", origDecimalSep); 354 } 355 fragment.innerHTML = temp; 356 }) 357 358 } 359 }, 360 "title": { 361 "visible": false 362 }, 363 "valueAxis": { 364 "label": { 365 "formatString": "u", 366 "unitFormatType": "FinancialUnits", 367 "visible": !self.opts.isTileMode 368 }, 369 "title": { 370 "visible": false 371 } 372 }, 373 374 "valueAxis2": { 375 "label": { 376 "formatString": "u", 377 "unitFormatType": "FinancialUnits", 378 "visible": !self.opts.isTileMode 379 }, 380 "title": { 381 "visible": false 382 } 383 }, 384 "categoryAxis": { 385 "axisTick": { 386 "visible": true 387 }, 388 "label": { 389 "formatString": "u", 390 "visible": "true" 391 }, 392 "title": { 393 "visible": false 394 } 395 } 396 }; 397 398 if (self.chartType == "Line-Column") { 399 chartOption.plotArea.dataShape = { 400 "primaryAxis": ["bar", "line", "bar"] 401 } 402 } 403 404 if (self.opts.isTileMode) { 405 chartOption.legend = { 406 visible: false 407 } 408 } 409 chartOption.legendGroup = { 410 layout: { 411 position: "top" 412 } 413 } 414 415 if (dataSource.strategyType == "forecast" && 416 dataSource.hasForecastData) { 417 var displayName = pa.translation.locale["legend_title_forecast"]; 418 chartOption.plotArea.dataPointStyle = { 419 rules: [{ 420 callback: function(data, extData) { 421 422 var count = JSON.parse(dataSource.strategyParams).m_number; 423 var cols = dataSource.cols; 424 cols = cols.slice(cols.length - count, cols.length).map(function(d) { 425 return d[0]; 426 }); 427 return cols.indexOf(data[dimKey]) != -1; 428 }, 429 properties: { 430 color: 'pink' 431 }, 432 displayName: displayName 433 }] 434 }; 435 if (dataSource.dashboardDetail.measures.list.length == 1) { 436 chartOption.plotArea.dataPointStyle.others = { 437 properties: { 438 color: 'rgb(92, 186, 230)' //TODO hard coded here 439 }, 440 displayName: self.getKey(dataSource.dashboardDetail.measures.list[0]), 441 } 442 chartOption.plotArea.dataPointStyleMode = "override"; 443 } else { 444 chartOption.plotArea.dataPointStyleMode = "update"; 445 } 446 447 } 448 449 return chartOption; 450 451 } 452 453 chart.prototype.draw = function() { 454 var self = this; 455 456 if (self.isInCockpit()) { 457 var reg = /#\[\d+\.{1}\d+\]/; 458 self.dataSource.rows.map(function(row){ 459 if (row.name && reg.test(row.name)) { 460 var placeHolder = row.name.match(reg); 461 if (placeHolder != null && placeHolder.length > 0) { 462 var translation = sap.b1.cockpit.tile.Util.getUDQ(placeHolder[0]); 463 row.name = row.name.replace(reg, translation); 464 } 465
465 } 466 }) 467 } 468 469 if (self.chartType == "Table") { 470 self.renderTable(); 471 return; 472 } 473 474 sap.viz.api.env.Resource.path('sap.viz.api.env.Template.loadPaths', [self.opts.templatePath]); 475 sap.viz.api.env.Template.set("standard_fiori", function() { 476 if (self.chartType == "Pie") { 477 //with pie chart, it will render multi pie in the page if multi measures selected 478 self.dataSource.dashboardDetail.measures.list.map(function(d, i) { 479 self.render(i); 480 }); 481 } else { 482 self.render(); 483 } 484 485 }); 486 } 487 488 chart.prototype.renderTable = function() { 489 var self = this; 490 var chartData = self.dataSource; 491 var transferredData; 492 transferredData = chartData.cols.map(function(row, i) { 493 return [i + 1].concat(row).concat(chartData.rows.map(function(row){ 494 return row.data[i];//sap.pervasive.common.formatNumber(row.data[i], row.metaType || row.type); 495 496 })); 497 }); 498 499 var measureIndex = chartData.col_titles.length; 500 var transferredTitiles; 501 if(self.hasLegend()){ 502 transferredTitiles = ["#"] 503 .concat(chartData.col_titles) 504 .concat(chartData.dashboardDetail.legendColors[0].legendColorValues.map(function(color){ 505 return self.getKey(chartData.dashboardDetail.measures.list[0]) 506 + " " + color.value; 507 })); 508 } else { 509 transferredTitiles = ["#"].concat(chartData.col_titles) 510 .concat(chartData.dashboardDetail.measures.list.map(function(measure){ 511 return self.getKey(measure); 512 })); 513 } 514 515 var containerId = self.canvas[0].attr("id"); 516 517 var tContainer = d3.selectAll(self.canvas[0]).selectAll(".tableContainer"); 518 var table = tContainer.selectAll(".tableChart"), 519 tHeader = tContainer.selectAll(".tableHeader"), 520 tBody = tContainer.selectAll(".tableBody"); 521 522 if (tContainer.length == 0 || tContainer[0][0] == null) { 523 tContainer = d3.select('#'+containerId) 524 .append("div") 525 .attr("class", "tableContainer") 526 .attr("style", "height:calc(85% - 20px); margin-left:20px; margin-right:20px; margin-top:10px; overflow-y:auto; -webkit-overflow-scrolling:touch;");; 527 528 table = tContainer 529 .append("table") 530 .attr("class", "tableChart") 531 .attr("cellspacing", "0") 532 .attr("style", "width:99%; text-align:left; font-weight: 400;"); 533 tHeader = table.append("thead") 534 .attr("class", "header") 535 .append("tr") 536 .attr("class", "tableHeader") 537 .attr("style", "background-repeat-x:repeat; background-repeat-y:no-repeat; background-position-x:0%; background-position-y:0%;"); 538 539 tBody = table.append("tbody") 540 .attr("class", "tableBody"); 541 542 543 if (!window.top.$.device.is.desktop) { 544 $('#canvas').on('touchstart', '.tableContainer', function(e) { 545 //prevent scrolling to the top or bottom 546 if (e.currentTarget.scrollTop === 0) { 547 e.currentTarget.scrollTop = 1; 548 } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.clientHeight) { 549 //scrollTop returns vertical scrollbar position, clientHeight includes padding but not border 550 e.currentTarget.scrollTop -= 1; 551 } 552 }); 553 $('#canvas').on('touchmove', '.tableContainer', function(e) { 554 //scrollHeight includes padding , but not border 555 if ($(this)[0].scrollHeight > $(this)[0].clientHeight) { 556 e.stopPropagation(); 557 } 558 }); 559 } 560 } 561 562 var tHColumn = tHeader 563 .selectAll("th.title") 564 .data(transferredTitiles, function(d){ 565 return d; 566 }); 567 tHColumn.exit().remove(); 568 tHColumn.enter() 569 .append("th") 570 .attr("class", "title") 571 .attr("title", function(d) { 572 return d; 573 }) 574 .text(function(d) { 575 return d; 576 }) 577 .attr("style", function(d,i){ 578 var style = "padding: 5px 3px; margin:0; border: solid 1px #a2acb1; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; text-align:center;" 579 if(i==0){ 580 style += " width:30px;" 581 } 582 return style; 583 }); 584 tHColumn.order(); 585 586 587 588 var trs = tBody.selectAll("tr").data(transferredData, function(d) { 589 return d; 590 }); 591 var tds = trs.enter() 592 .append("tr") 593 .attr("style", function(d, rowIndex) { 594 if (rowIndex % 2 == 0) { 595 return " background-color: rgb(249,249,249);" 596 } 597 }) 598 .on("mouseover", function(d, i) { 599 $(this).css({ 600 'background-color': '#fef09e', 601 'color': '#000' 602 }) 603 }) 604 .on("mouseout", function(d, i) { 605 $(this).css({ 606 "background": i % 2 == 0 ? "rgb(249,249,249)" : "
606inherit", 607 'color': '#000' 608 }) 609 }) 610 .selectAll("td") 611 .data(function(d) { 612 return d; 613 }) 614 .enter() 615 .append("td") 616 .attr("class", "val_cell") 617 .attr("title", function(d) { 618 return d; 619 }) 620 .text(function(d) { 621 //TODO should have format here 622 return d; 623 }) 624 .attr("style", function(d, colIndex, rowIndex) { 625 var result = "padding: 5px 3px; margin:0; border: solid 1px #a2acb1; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;" 626 if (colIndex == 0) { 627 result += " text-align: center;" 628 } else if (colIndex > measureIndex) { 629 result += " text-align: right;" 630 } else { 631 result += " text-align: left;" 632 } 633 return result; 634 }); 635 636 trs.exit().remove(); 637 trs.order(); 638 transferredData = null; 639 transferredTitiles = null; 640 tContainer = null; 641 table = null; 642 tHeader = null; 643 tBody = null; 644 if(self.afterRender){ 645 self.afterRender(); 646 } 647 } 648 649 650 chart.prototype.render = function(idx) { 651 var self = this; 652 653 var data = self.transformData(); 654 var dataset = new sap.viz.api.data.FlatTableDataset(); 655 dataset.data(data); 656 var container = self.canvas[0]; 657 var option = self.getChartOption(); 658 var mCount = self.dataSource.dashboardDetail.measures.list.length; 659 660 if (self.opts.isTileMode) { 661 self.canvas.css({ 662 position: "static", 663 width: "100%", 664 height: self.dataSource.hasTimerSlider ? "calc(100% - 25px)" : "100%" 665 }); 666 } 667 //here start to handle the case of multi measure for pie 668 if (idx !== undefined && mCount > 1) { 669 self.canvas.append("<div id='chart_container_" + idx + "_" + self.canvas.attr("id") + "'>"); 670 container = $("#" + "chart_container_" + idx + "_" + self.canvas.attr("id"))[0]; 671 672 var flag = $(container.parentElement).width()/$(container.parentElement).height(); 673 //TODO magic number here to predict the proper layout of 674 //multi-pie chart in different width and length setting 675 if(flag >= 2){ 676 $(container).css({ 677 width: mCount==3? "33%" : "50%", 678 height: "100%", 679 float: "left" 680 }); 681 }else if( flag <= 0.6 ){ 682 $(container).css({ 683 width: "100%", 684 height: mCount==3? "33%" : "50%", 685 float: "left" 686 }); 687 }else{ 688 $(container).css({ 689 width: "50%", 690 height: mCount==3? "50%" : "100%", 691 position: "relative", 692 top: idx === 2 && !self.opts.isTileMode? "-100px" : "0px", 693 float: "left" 694 }); 695 } 696 697 } 698 699 var VizFrame = sap.viz.vizframe.VizFrame; 700 var chart = new VizFrame({ 701 type: self.getChartType(), 702 data: dataset, 703 container: container, 704 properties: option, 705 bindings: self.getBinding(idx) 706 },{ 707 controls:{ 708 morpher:{ 709 //enabled: !this.opts.noAnimate && self.chartType !== "Rank" 710 enabled:false 711 } 712 } 713 }); 714 715 chart.on("renderComplete.viz", function() { 716 if(self.opts.rightClickCallback){ 717 self.canvas.on("mousedown", "svg g.v-m-plot", self.opts.rightClickCallback); 718 } 719 self.canvas[0].oncontextmenu = function() { 720 return false; 721 }; 722 723 if (idx > 0) { 724 //here handles multi-pie chart to show only 1 legend 725 $("#chart_container_" + idx + "_" + self.canvas.attr("id") + " .v-m-legendGroup").remove(); 726 } 727 var root = d3.selectAll(self.canvas); 728 if (self.chartType == "Rank") { 729 /* 730 * Rank chart currently not supported as a cvom standard chart type. 731 * To implement rank, here uses a normal line chart and rebuild the Y axis. 732 * It may cause some accuracy issue as we try to revert the scale from output to input 733 */ 734 var ticks = root.selectAll(".v-m-yAxis .v-label-group text"); 735 var points = root.selectAll(".v-datapoint-group>g").selectAll(".v-datapoint"); 736 var data = d3.merge(points).map(function(d) { 737 var bindData = d3.select(d).data()[0]; 738 return { 739 input: bindData[bindData.measureNames], 740 output: d3.select(d).attr("transform").split(",")[1].replace(")", "") - 0 741 }; 742 }) 743 744 var domain = d3.extent(data, function(d) { 745 return d.input; 746 }) 747 748 var range = d3.extent(data, function(d) { 749 return Math.round(d.output); 750 }); 751 752 var oldScale = d3.scale.linear() 753 .domain(domain) 754 .range(range.reverse()); 755 756 if (ticks[0].length > 1) { 757 var rangeMaxExt = d3.select(ticks[0][0]).attr("y"); 758 var domainMaxExt = toRaw(d3.select(ticks[0][0]).text()); //oldScale.invert(rangeMaxExt); 759 var rangeMinExt = d3.select(ticks[0][ticks[0].length - 1]).attr("y"); 760 var domainMinExt = toRaw(d3.select(ticks[0][ticks[0].length - 1]).text()) //oldScale.invert(rangeMinExt); 761 762 var scale = d3.scale.linear() 763 .domain([domainMinExt, domainMaxExt]) 764 .range([rangeMaxExt, rangeMinExt]); 765 } else { 766 var scale = d3.scale.linear() 767 .domain(domain) 768 .range([range[1], range[0]]); 769 }
770 Array.prototype.map.apply(points, [function(group, i) { 771 group.map(function(d) { 772 var el = d3.select(d); 773 var transform = el.attr("transform").split(","); 774 775 el.attr("transform", function(d) { 776 var output = scale(oldScale.invert(transform[1].replace(")", "") - 0)); 777 return transform[0] + ", " + output + ")"; 778 }) 779 }) 780 }]) 781 782 var path = root 783 .selectAll(".v-lines-group") 784 .selectAll("path"); 785 786 Array.prototype.map.apply(path, [function(d, i) { 787 var el = d3.selectAll(d); 788 var temp = el.attr("d").split("L").map(function(d, i) { 789 var xy = d.split(","); 790 xy[1] = scale(oldScale.invert(xy[1])); 791 return (i == 0 ? "" : "L") + xy.join(","); 792 }).join(""); 793 el.attr("d", temp); 794 }]) 795 796 var positions = Array.prototype.map.apply(ticks[0], [function(tick, i) { 797 return d3.select(tick).attr("y") 798 }]).reverse(); 799 800 Array.prototype.map.apply(ticks[0], [function(tick, i) { 801 d3.select(tick).attr("y", function(d) { 802 return positions[i]; 803 }) 804 }]) 805 806 } 807 808 /* 809 * For line chart with forecast, the plot rule could only change state of points not the lines. 810 * We should manually apply the color of line here 811 */ 812 if (self.dataSource.strategyType == "forecast" && 813 self.dataSource.hasForecastData && 814 self.chartType == "Line") { 815 var linesGroup = root.selectAll(".v-lines-group"); 816 var count = JSON.parse(self.dataSource.strategyParams).m_number; 817 818 var path = Array.prototype.map.apply( 819 linesGroup.selectAll("path"), [function(d) { 820 return d3.select(d[0]).attr("d"); 821 }] 822 ) 823 824 path.map(function(d, idx) { 825 var temp = d.split("L"); 826 var newPath = "M" + temp.slice(temp.length - count - 1, temp.length).join("L"); 827 d3.select(linesGroup[0][idx]).append("path") 828 .attr("d", newPath) 829 .attr("stroke", "pink") 830 .attr("fill", "none") 831 .attr("stroke-width", "2"); 832 }) 833 } 834 835 if(idx){ 836 if(!self._charts){ 837 self._charts = []; 838 } 839 self._charts[idx] = chart; 840 }else{ 841 self._chart = chart; 842 } 843 844 if(self.afterRender){ 845 self.afterRender(); 846 } 847 848 }) 849 850 851 /** 852 * Try to revert the formatted data into orginal value. This method only used by rank to rebuild the Y scale 853 */ 854 var toRaw = function(text) { 855 if (text.indexOf("k") != -1) { 856 return text.replace("k", "") * 1000; 857 } 858 859 if (text.indexOf("m") != -1) { 860 return text.replace("k", "") * 1000000; 861 } 862 return text - 0; 863 } 864 } 865 866 /** 867 * Try to invoke cvom api of chart.destory if possible which will improve the performance 868 */ 869 chart.prototype.destroy = function() { 870 var self = this; 871 self.canvas[0].oncontextmenu = undefined; 872 self.canvas.off("mousedown"); 873 874 if (self.chartType == "Table") { 875 self.canvas.empty(); 876 return; 877 } 878 if (self._charts) { 879 self._charts.map(function(d) { 880 d.destroy(); 881 }) 882 self.canvas.empty(); 883 self = undefined; 884 return; 885 } 886 try { 887 self._chart.destroy(); 888 self = undefined; 889 } catch (e) { 890 console.log(e); 891 self.canvas.empty(); 892 self = undefined; 893 } 894 return; 895 896 } 897 return chart; 898})(jQuery); 899 900(function($) { 901 "use strict"; 902 $.fn.chart = (function() { 903 904 var chartMap = {}; 905 return function(options, chartData, afterRender) { 906 907 var target = $(this); 908 var key = target.attr("id"); 909 if (!key) { 910 key = new Date() - 0; 911 target.attr("id", key); 912 }
913 var oldChart = chartMap[key]; 914 if (oldChart){ 915 if(oldChart.chartType =="Table" && chartData.chart_type == "Table"){ 916 oldChart.dataSource = chartData; 917 oldChart.renderTable(); 918 return; 919 } 920 oldChart.destroy(); 921 oldChart = undefined; 922 } 923 924 var newChart = new chart(target, options, chartData, afterRender); 925 newChart.draw(); 926 chartMap[key] = newChart; 927 } 928 929 })(); 930})(jQuery);
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.