PageSourceSearch

https://muchoperro.com/webx/~1689229967343~/resources/lib/cvom/viz_base.js

js muchoperro.com collected 2026-09-29 05:58:55 UTC 33,438 bytes, 930 lines download raw bytes

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.